home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume10 / parseargs < prev    next >
Encoding:
Text File  |  1990-02-16  |  65.3 KB  |  2,935 lines

  1. Newsgroups: comp.sources.misc
  2. organization: Xenix Support, FICC
  3. from: peter@ficc.uu.net (Peter da Silva)
  4. subject: v10i071: Improvements to Parseargs
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 10, Issue 71
  8. Submitted-by: peter@ficc.uu.net (Peter da Silva)
  9. Archive-name: parseargs
  10.  
  11. You're missing some stuff I sent in. Some serious improvements to parseargs,
  12. for example.
  13.  
  14. :
  15. #! /bin/sh
  16. # This is a shell archive, created at Ferranti International Controls Corp.
  17. # by peter (peter da silva, +1 713 274 5180) on Wed Feb  7 08:10:16 1990
  18. # Remove anything before the "#! /bin/sh" line, then unpack it by saving
  19. # it into a file and typing "sh file".  If you do not have sh, you need 
  20. # unshar, a dearchiving program which is widely available.  In the absolute
  21. # wost case, you can crack the files out by hand.
  22. # If the archive is complete, you will see the message "End of archive."
  23. # at the end.
  24. # This archive contains the following files...
  25. # 'README'
  26. # 'README.PDS'
  27. # 'Makefile'
  28. # 'funclist.h'
  29. # 'parseargs.h'
  30. # 'useful.h'
  31. # 'ckalloc.c'
  32. # 'argtype.c'
  33. # 'fp_argtype.c'
  34. # 'funclist.c'
  35. # 'openpath.c'
  36. # 'amiga_args.c'
  37. # 'unix_args.c'
  38. # 'syserr.c'
  39. # 'traceset.c'
  40. # 'stest.c'
  41. # 'ckalloc.3'
  42. # 'funclist.3'
  43. # 'openpath.3'
  44. # 'parseargs.3'
  45. # 'syserr.3'
  46. # 'trace.3'
  47. # To extract them, run the following through /bin/sh
  48. echo x - README
  49. sed 's/^X//' > README << '//END_OF_FILE'
  50. X
  51. X              NIFTY UTILITY LIBRARY
  52. X
  53. X                 Eric P. Allman
  54. X            University of California
  55. X              Berkeley, California
  56. X                eric@Berkeley.EDU
  57. X
  58. X
  59. XSUMMARY
  60. X    This directory contains a subset of a utility library that I have
  61. X    used (in various forms) for several years now.  This particular
  62. X    version is rather sparse, being a relatively recent reimplementation.
  63. X
  64. X    I am making this available as a result of the rather surprising
  65. X    response to my C Advisor column in UNIX Review Vol. 7 No. 11 on
  66. X    argument parsing, in which I described an alternative to getopt.
  67. X    Several dozen people have asked for the source code -- an amazing
  68. X    number, considering that in the four years prior to this column,
  69. X    I have gotten perhaps six letters in toto.
  70. X
  71. X    Rather than limiting this distribution to the single argument
  72. X    parsing module, I have added several other routines, many of which
  73. X    my more faithful readers will recognize.
  74. X
  75. XCOPY/REUSE POLICY
  76. X    Permission is hereby granted to freely copy and redistribute this
  77. X    software, provided that the author is clearly credited in all
  78. X    copies and derivations.  Neither the name of the author nor that
  79. X    of the University may be used to endorse or promote products
  80. X    derived from this software without specific written permission.
  81. X    This software is provided ``As Is'' and without any express or
  82. X    implied warranties.
  83. X
  84. XCONTENTS
  85. X    This directory contains:
  86. X        README -- this file.
  87. X        Makefile -- a makefile for the library.
  88. X        useful.h -- a general header file, used by most everything.
  89. X        ckalloc.c -- an interface to malloc(3) which diagnoses
  90. X            out of memory conditions.  This topic was discussed
  91. X            in the C Advisor column in UNIX Review Vol. 7 No 7.
  92. X        ckalloc.3 -- documentation for ckalloc.
  93. X        funclist.h -- a header file specific to the function list
  94. X            routines in funclist.c.
  95. X        funclist.c -- routines that provide lists of ``callout''
  96. X            functions, used by several of the other routines
  97. X            to handle errors.
  98. X        funclist.3 -- documentation for the funclist routines.
  99. X        lwp_dump.c -- a routine to dump the state of the LightWeight
  100. X            Process system in SunOS 4.0 -- this isn't used, but
  101. X            may be useful to some of you.
  102. X        openpath.c -- a routine to open a file, searching through
  103. X            a path of directories to find it.
  104. X        openpath.3 -- documentation for openpath.
  105. X        parseargs.h -- headers for the argument parser.
  106. X        parseargs.c -- a command line argument parser.  Popular
  107. X            response to my C Advisor column about this routine
  108. X            in UNIX Review Vol. 7 No. 11 prompted me to make
  109. X            this distribution available.
  110. X        parseargs.3 -- documentation for parseargs.
  111. X        fp_args.c -- argument value parsers for floating point values;
  112. X            used by parseargs.  This is only included if you need
  113. X            FP values.  I had to break this out because RISC/os
  114. X            4.01 from Mips doesn't seem to support strtod in the
  115. X            BSD environment.  You may find you need to include
  116. X            -lm for this to work.
  117. X        syserr.c -- error message printing routines.  A version of
  118. X            this was discussed in the C Advisor column in UNIX
  119. X            Review, Vol. 7 No. 7.
  120. X        syserr.3 -- documentation for syserr.
  121. X        traceset.c -- routines to set trace flags.  The flags are
  122. X            tested by macros contained in useful.h.
  123. X        trace.3 -- documentation for the trace routines and macros.
  124. X        stest.c -- a small test program for the argument parser.
  125. X
  126. X    The parseargs routine really ought to have a way of matching a
  127. X    list (e.g., return the rest of argv).  This isn't especially
  128. X    hard to do, but I haven't gotten around to it yet.
  129. X
  130. XDISCLAIMERS
  131. X    I hacked this code up to (hopefully) work on ANSI C compilers,
  132. X    since several readers seem to be interested in this sort of thing.
  133. X    I can't claim to have really tested this.
  134. X
  135. X    The original version was tested under SunOS 4.0 on SPARC architectures.
  136. X    The version you see has been loosely tested on a Mips M/2000 running
  137. X    RISC/os 4.01; I have only tried it in the BSD environment, and that
  138. X    only loosely.
  139. X
  140. XACKNOWLEDGEMENTS
  141. X    I wrote the first version of this code while working at the
  142. X    International Computer Science Institute in Berkeley, CA.
  143. X
  144. X$Header: README,v 2.1 89/12/30 20:59:14 eric Exp $
  145. //END_OF_FILE
  146. echo x - README.PDS
  147. sed 's/^X//' > README.PDS << '//END_OF_FILE'
  148. XUpdate to parseargs by Peter da Silva (peter@ficc.uu.net).
  149. X(second update: more improvements to arg parsing, argChar type)
  150. X(third update, return to original calling sequence, argList type)
  151. X
  152. XParseargs is a really nifty set of routines, but it doesn't fit too
  153. Xwell with standard UNIX semantics. In particular, you can get into a
  154. Xlot of trouble using it in a script if it drops into interactive mode
  155. Xon you. Also, it's not as useful as it could be for non-UNIX systems.
  156. XTo make it work better, I've made a couple of changes.
  157. X
  158. XIt compiled straight out of the box on System III once I'd provided
  159. Xbcopy, bcmp, and strtol. The strtol I've provided is almost totally
  160. Xuntested, but hopefully you won't need to use it. It's only for folks with
  161. Xold UNIX systems.
  162. X
  163. XFirst change was to disable the interactive prompting for arguments.
  164. XI think that's inconsistent with usual UNIX semantics. You can undo
  165. Xthis change by #defining INTERACTIVE when compiling parseargs.c.
  166. X
  167. XThe second change was to allow for a trailing list of arguments. I
  168. Xoriginally implemented this by changing the calling sequence to parseargs.
  169. XOn reflection this would just produce incompatibilities, so I added a
  170. Xnew "type", argList. This handles a pointer to a list of names:
  171. X
  172. Xstruct namelist {
  173. X    struct namelist *nl_next;
  174. X    char *nl_name;
  175. X};
  176. X
  177. XThis is implemented with some "magic" in parseargs, and perhaps it would
  178. Xdo better as an additional flag, ARGLIST, and a set of listType routines
  179. Xto handle them. Also, it currently keeps the list in LIFO order. It would
  180. Xbe more convenient in FIFO order, though this would take a little more
  181. Xwork to implement (basically just stepping through the list in argList to
  182. Xfind the tail, instead of inserting at the head), and can be fixed in a
  183. Xsingle pass after parseargs returns with (say) !argv = reverselist(argv)!:
  184. X
  185. Xstruct namelist *reverselist(from)
  186. Xstruct namelist *from;
  187. X{
  188. X    struct namelist *to, *tmp;
  189. X
  190. X    to = NULL;
  191. X    while(from) {
  192. X        tmp = from->nl_next; /* remove top from old list */
  193. X        from = from->nl_next;
  194. X        tmp->nl_next = to; /* insert top in new list */
  195. X        to = tmp;
  196. X    }
  197. X    return to;
  198. X}
  199. X
  200. XThe final change is the addition of a 'argChar' type. This parses character
  201. Xarguments (such as the '-T' option to 'awk'), accepting single characters,
  202. X'\nnn' octal escapes, and '^X' for control characters.
  203. X
  204. XParseargs itself no longer uses ckalloc, traceset, funclist, and so on.
  205. Xthese routines are pretty cool, but when you're grafting parseargs onto
  206. Xan existing program they just get in the way. Also, it's possible to make
  207. Xparseargs fail in a cleaner fashion by handling out-of-memory cases myself.
  208. XCertainly there's not going to be any loose memory lying around to be
  209. Xcollected when parseargs starts up! To turn on TRACE and the funclist code
  210. Xjust add -DTRACESTUFF and -DFUNCLISTSTUFF to the Makefile.
  211. X
  212. XAlso, the error messages have been made a bit more descriptive. Instead
  213. Xof saying "stest: value required for -c flag", it prints "stest: RepCount
  214. Xrequired for -c flag". The ad_prompt element should relly be a descriptive
  215. Xword that can be used in a sentence... or for non_UNIX systems a multi-
  216. Xcharacter or keyword based flag. I have an Amiga version included, for
  217. Xexample, that uses keyword syntax. In that version, the usage message reads:
  218. X
  219. XUsage: amiga_test <name> [GROUP <newsgroup>]... [REP <repcount>] +
  220. X    [DIR <dirname>] [X] [Y] [Z] [TAB <tabchar>] [<file>]...
  221. X
  222. XInstead of:
  223. X
  224. XUsage: unix_test <Name> [-n <newsGROUP>]... [-c <REPcount>] \
  225. X    [-d <DIRname>] [-x] [-y] [-z] [-t <TABchar>] [<File>]...
  226. X
  227. XThis would solve the old problem of UNIX programs sticking out like a
  228. Xsore thumb in other operating systems.
  229. X
  230. XThe Amiga version still needs to prompt for options if called with a
  231. Xsingle '?' as an argument. This may require some redesign: it's almost
  232. Xcertainly not going to be possible to stuff *extra* file names into
  233. Xargv. Perhaps something like:
  234. X
  235. X    parseargs(&argc, &argv, "File");
  236. X
  237. X????????
  238. //END_OF_FILE
  239. echo x - Makefile
  240. sed 's/^X//' > Makefile << '//END_OF_FILE'
  241. X# $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $
  242. X
  243. XTARGET=        /usr
  244. XLIBDIR=        /lib
  245. XINCDIR=        ${TARGET}/include
  246. X
  247. XINCLUDES=    -I.
  248. XMODEL=        -Ms
  249. XMODELNAME=    S
  250. XSTYLE=        unix
  251. XO=        -O
  252. XOPTIONS=    # -DINTERACTIVE -DTRACESTUFF -DFUNCLISTSTUFF
  253. X
  254. XCFLAGS=        ${MODEL} ${INCLUDES} $O ${OPTIONS}
  255. X
  256. XOFILES=        ckalloc.o \
  257. X        argtype.o \
  258. X        fp_argtype.o \
  259. X        funclist.o \
  260. X        openpath.o \
  261. X        ${STYLE}_args.o \
  262. X        syserr.o \
  263. X        traceset.o \
  264. X        strtol.o
  265. X
  266. XHFILES=        funclist.h \
  267. X        parseargs.h \
  268. X        useful.h
  269. X
  270. XCFILES=        ckalloc.c \
  271. X        argtype.c \
  272. X        fp_argtype.c \
  273. X        funclist.c \
  274. X        openpath.c \
  275. X        amiga_args.c \
  276. X        unix_args.c \
  277. X        syserr.c \
  278. X        traceset.c \
  279. X        stest.c
  280. XMANFILES=    ckalloc.3 \
  281. X        funclist.3 \
  282. X        openpath.3 \
  283. X        parseargs.3 \
  284. X        syserr.3 \
  285. X        trace.3
  286. XXXFILES=    README \
  287. X        README.PDS \
  288. X        Makefile
  289. X
  290. XOBJS=        ${OFILES}
  291. XSRCFILES=    ${XXFILES} ${HFILES} ${CFILES} ${MANFILES}
  292. XLIBARGS=    ${MODELNAME}lib${STYLE}_args.a
  293. XLIBFILE=    ${MODELNAME}libparse.a
  294. XLOCLIBS=    ${LIBARGS}
  295. XSYSLIBS=    -lm
  296. XLIBS=        ${LOCLIBS} ${SYSLIBS}
  297. XSHAR=        shar
  298. X
  299. X${STYLE}_test: stest.o ${LOCLIBS}
  300. X    ${CC} ${CFLAGS} -o ${STYLE}_test stest.o ${LIBS}
  301. X
  302. Xckalloc.o funclist.o syserr.o: funclist.h
  303. X
  304. X${STYLE}_args.o: parseargs.h
  305. X
  306. X${LIBARGS}: ${OBJS}
  307. X    ar rvu $@ ${OBJS}
  308. X    ranlib $@
  309. X
  310. Xinstall: ${INCDIR}/parseargs.h ${LIBDIR}/${LIBFILE}
  311. X
  312. X${INCDIR}/parseargs.h: parseargs.h
  313. X    (cd ${INCDIR}; rm -f ${HFILES})
  314. X    cp ${HFILES} ${INCDIR}
  315. X
  316. X${LIBDIR}/${LIBFILE}: ${LIBARGS}
  317. X    rm -f ${LIBDIR}/${LIBFILE}
  318. X    cp ${LIBARGS} ${LIBDIR}/${LIBFILE}
  319. X    ranlib ${LIBDIR}/${LIBFILE}
  320. X
  321. Xshar: parseargs.shar
  322. X
  323. Xparseargs.shar: ${SRCFILES}
  324. X    rm -f parseargs.shar
  325. X    ${SHAR} ${SRCFILES} > parseargs.shar
  326. X
  327. Xclean:
  328. X    rm -f ${OFILES} ${LIBARGS} ${STYLE}_test tags stest.o
  329. X
  330. Xtags: ${CFILES} ${HFILES}
  331. X    ctags ${CFILES} ${HFILES}
  332. //END_OF_FILE
  333. echo x - funclist.h
  334. sed 's/^X//' > funclist.h << '//END_OF_FILE'
  335. X/*
  336. X**  FUNCLIST.H -- headers for function list routines
  337. X**
  338. X**    $Header: funclist.h,v 2.0 89/12/24 00:56:23 eric Exp $
  339. X**
  340. X**    Each entry in this list contains a pointer to a function to be
  341. X**    invoked, and an integer argument to be passed to it.
  342. X**
  343. X**    Author:
  344. X**        Eric Allman
  345. X**        University of California, Berkeley
  346. X*/
  347. X
  348. X#ifndef FUNCLIST
  349. X
  350. X#ifndef _USEFUL_H_
  351. X#include <useful.h>
  352. X#endif
  353. X
  354. X#define FUNCLIST    struct _funclist
  355. X
  356. XFUNCLIST
  357. X{
  358. X    FUNCLIST    *_fl_next;    /* next in chain */
  359. X    VOID        (*_fl_func)();    /* function to invoke */
  360. X    ARBPTR        _fl_arg;    /* first argument */
  361. X};
  362. X
  363. X#define FUNCLISTNULL    ((FUNCLIST *) NULL)
  364. X
  365. X#endif
  366. //END_OF_FILE
  367. echo x - parseargs.h
  368. sed 's/^X//' > parseargs.h << '//END_OF_FILE'
  369. X/*
  370. X**  PARSEARGS.H -- declarations for argument vector parser
  371. X**
  372. X**    $Header: parseargs.h,v 2.0 89/12/24 00:56:29 eric Exp $
  373. X**
  374. X**    Author:
  375. X**        Eric Allman
  376. X**        University of California, Berkeley
  377. X*/
  378. X
  379. X#ifndef ARGDESC
  380. X
  381. X#ifndef _USEFUL_H_
  382. X#include <useful.h>
  383. X#endif
  384. X
  385. X#define ARGDESC        struct _argdesc
  386. X
  387. XARGDESC
  388. X{
  389. X    char    ad_name;    /* flag name */
  390. X    char    ad_flags;    /* flags */
  391. X    BOOL    (*ad_type) ARGS((ARGDESC *, char *, BOOL));
  392. X                /* function to parse value */
  393. X    ARBPTR    ad_valp;    /* pointer to value storage area */
  394. X    char    *ad_prompt;    /* prompt string */
  395. X};
  396. X
  397. X/* bits for ad_flags */
  398. X#define ARGREQ        0x01    /* required argument */
  399. X#define ARGOPT        0x00    /* optional argument pseudo-flag */
  400. X#define ARGHIDDEN    0x02    /* don't display in usage message */
  401. X#define ARGGIVEN    0x08    /* (internal) argument has been specified */
  402. X
  403. X/* types available for ad_type */
  404. Xextern BOOL    argBool ARGS((ARGDESC *, char *, BOOL));
  405. Xextern BOOL    argChar ARGS((ARGDESC *, char *, BOOL));
  406. Xextern BOOL    argStr ARGS((ARGDESC *, char *, BOOL));
  407. Xextern BOOL    argInt ARGS((ARGDESC *, char *, BOOL));
  408. Xextern BOOL    argShort ARGS((ARGDESC *, char *, BOOL));
  409. Xextern BOOL    argLong ARGS((ARGDESC *, char *, BOOL));
  410. Xextern BOOL    argFloat ARGS((ARGDESC *, char *, BOOL));
  411. Xextern BOOL    argDouble ARGS((ARGDESC *, char *, BOOL));
  412. Xextern BOOL    argList ARGS((ARGDESC *, char *, BOOL));
  413. X
  414. Xstruct namelist {
  415. X    struct namelist *nl_next;
  416. X    char *nl_name;
  417. X};
  418. X
  419. X#define ENDOFARGS    { '\0' }
  420. X
  421. X#endif
  422. //END_OF_FILE
  423. echo x - useful.h
  424. sed 's/^X//' > useful.h << '//END_OF_FILE'
  425. X/*
  426. X**  USEFUL.H -- various definitions of general interest
  427. X**
  428. X**    $Header: useful.h,v 2.0 89/12/24 00:56:33 eric Exp $
  429. X**
  430. X**    Author:
  431. X**        Eric Allman
  432. X**        University of California, Berkeley
  433. X*/
  434. X
  435. X#ifndef _USEFUL_H_
  436. X#define _USEFUL_H_
  437. X
  438. X#include <stdio.h>
  439. X
  440. X/* give a stab at the multiple-language dilemma */
  441. X#ifdef __STDC__
  442. X#define ARGS(x)        x
  443. X#define NOARGS        (void)
  444. X#define __ANSI_C__
  445. X#else
  446. X#if defined(c_plusplus) || defined(__cplusplus)
  447. X#define ARGS(x)        x
  448. X#define NOARGS        ()
  449. X#define __ANSI_C__
  450. X#else
  451. X#define ARGS(x)        ()
  452. X#define NOARGS        ()
  453. X#endif
  454. X#endif
  455. X
  456. X#ifndef VOID
  457. X#ifdef __ANSI_C__
  458. X#define VOID        void
  459. X#else
  460. X#define VOID        int
  461. X#endif
  462. X#endif
  463. X
  464. X#ifndef TRUE
  465. X#define TRUE        1
  466. X#define FALSE        0
  467. X#endif
  468. X
  469. X#ifndef BOOL
  470. X#define BOOL        char
  471. X#endif
  472. X
  473. X#ifndef STATIC
  474. X#ifndef NODEBUG
  475. X#define STATIC
  476. X#else
  477. X#define STATIC        static
  478. X#endif
  479. X#endif
  480. X
  481. X#ifndef EXTERN
  482. X#define EXTERN        extern
  483. X#endif
  484. X
  485. X#ifndef CONST
  486. X#ifdef __ANSI_C__
  487. X#define CONST        const
  488. X#else
  489. X#define CONST
  490. X#endif
  491. X#endif
  492. X
  493. X#ifndef NULL
  494. X#define NULL        0
  495. X#endif
  496. X
  497. X#ifndef CHARNULL
  498. X#define CHARNULL    ((char *) NULL)
  499. X#endif
  500. X
  501. X#define FILENULL    ((FILE *) NULL)
  502. X
  503. X#ifdef __ANSI_C__
  504. X#define ARBPTR        void *
  505. X#else
  506. X#define ARBPTR        char *
  507. X#endif
  508. X#define __        (ARBPTR)
  509. X#define ARBNULL        (__ NULL)
  510. X
  511. X#ifndef TRACESTUFF
  512. X#define NODEBUG
  513. X#endif
  514. X
  515. X#ifndef NODEBUG
  516. X#define _TRACE_SIZE    200
  517. Xextern unsigned char    _TraceVect[_TRACE_SIZE];
  518. X#define TRACEF(f, l)    (_TraceVect[f] >= l)
  519. X#define TRACE(f, l, m)    (TRACEF(f, l) ? printf m : 0)
  520. X#else
  521. X#define TRACEF(f, l)    (FALSE)
  522. X#define TRACE(f, l, m)
  523. X#endif
  524. X
  525. X#ifdef lint
  526. X#define VERSIONID(v)
  527. X#else
  528. X#define VERSIONID(v)    static char _Version[] = v;
  529. X#endif
  530. X
  531. X#define BITSET(b, w)    (((b) & (w)) != 0)
  532. X
  533. X#ifdef __STDC__
  534. X#include <string.h>
  535. X#else
  536. Xextern char    *strchr ARGS((char *, char));
  537. Xextern char    *strrchr ARGS((char *, char));
  538. X#endif
  539. X
  540. Xextern ARBPTR    ckalloc ARGS((unsigned int));
  541. X
  542. X#define MAXINPUTLINE    200        /* maximum string input line */
  543. X#define MAXWORDLEN    100        /* maximum word (token) length */
  544. X
  545. X#ifndef BSD
  546. X#define bcopy(f,t,l) memcpy(t,f,l)
  547. X#define bcmp(s,t,l) memcmp(s,t,l)
  548. X#endif
  549. X
  550. X#endif /* _USEFUL_H_ */
  551. //END_OF_FILE
  552. echo x - ckalloc.c
  553. sed 's/^X//' > ckalloc.c << '//END_OF_FILE'
  554. X#include <useful.h>
  555. X#include <funclist.h>
  556. X
  557. XVERSIONID("$Header: ckalloc.c,v 2.0 89/12/24 00:56:21 eric Exp $");
  558. X
  559. X/*
  560. X**  CKALLOC -- allocate memory, checking for error conditions
  561. X**
  562. X**    If we cannot allocate memory, we call the list of functions
  563. X**    in OutOfMemoryFuncs.  We then try again.  If the second attempt
  564. X**    fails, we terminate the process.
  565. X**
  566. X**    Parameters:
  567. X**        size -- the number of bytes of memory to be allocated.
  568. X**
  569. X**    Returns:
  570. X**        A pointer to the allocated memory.
  571. X**        Never returns if memory cannot be allocated.
  572. X**
  573. X**    Side Effects:
  574. X**        As implied by memory allocation.
  575. X**
  576. X**    Globals:
  577. X**        OutOfMemoryFuncs -- a FUNCLIST that is called when memory
  578. X**            cannot be allocated.
  579. X**
  580. X**    Author:
  581. X**        Eric Allman
  582. X**        University of California, Berkeley
  583. X*/
  584. X
  585. XFUNCLIST    *OutOfMemoryFuncs =    FUNCLISTNULL;
  586. X
  587. XARBPTR
  588. Xckalloc(size)
  589. X    unsigned int size;
  590. X{
  591. X    ARBPTR p;
  592. X    extern char *malloc ARGS((unsigned int));
  593. X
  594. X    p = __ malloc(size);
  595. X    if (p == ARBNULL)
  596. X    {
  597. X        funclist_call(OutOfMemoryFuncs, ARBNULL);
  598. X        p = __ malloc(size);
  599. X        if (p == ARBNULL)
  600. X            syserr("ckalloc: out of memory");
  601. X    }
  602. X    return (p);
  603. X}
  604. //END_OF_FILE
  605. echo x - argtype.c
  606. sed 's/^X//' > argtype.c << '//END_OF_FILE'
  607. X#include <useful.h>
  608. X#include <parseargs.h>
  609. X#include <ctype.h>
  610. X
  611. X#ifdef __STDC__
  612. Xtypedef void *pointer;
  613. X#else
  614. Xtypedef char *pointer;
  615. X#endif
  616. X
  617. Xextern pointer malloc();
  618. X
  619. X#define ALL_AD        ad = argd; ad->ad_name != '\0'; ad++
  620. X#define ALL_DEFS    ad = _DefaultArgs; ad->ad_name != '\0'; ad++
  621. X
  622. Xextern char    *ProgName;
  623. X
  624. X/*
  625. X**  ARGtype -- argument translation routines.
  626. X**
  627. X**    Each of these converts a parameter value to the internal form,
  628. X**    including validity checking.  Their parameters and return values
  629. X**    all behave identically.
  630. X**
  631. X**    Parameters:
  632. X**        ad -- the argument descriptor for this parameter.
  633. X**        vp -- a pointer to the string input value.
  634. X**        copyf -- if TRUE, the value will be destroyed later,
  635. X**            and so should be copied if it will be retained
  636. X**            (as for a string).
  637. X**
  638. X**    Returns:
  639. X**        TRUE -- if the conversion was successful.  The actual
  640. X**            value should be stored in the location indicated
  641. X**            by ad->ad_valp.
  642. X**        FALSE -- if the conversion failed.  The reason for failure
  643. X**            should be diagnosed using usrerr().
  644. X**
  645. X**    Side Effects:
  646. X**        The value should be stored through ad->ad_valp.
  647. X*/
  648. X
  649. XBOOL
  650. XargStr(ad, vp, copyf)
  651. X    register ARGDESC *ad;
  652. X    register char *vp;
  653. X    BOOL copyf;
  654. X{
  655. X    char *cp;
  656. X
  657. X    if (copyf)
  658. X    {
  659. X        register int i;
  660. X
  661. X        i = strlen(vp) + 1;
  662. X        cp = (char *) malloc(i);
  663. X        if(!cp) {
  664. X            usrerr("out of memory parsing %s", ad->ad_prompt);
  665. X            return FALSE;
  666. X        }
  667. X        bcopy(vp, cp, i);
  668. X    }
  669. X    else
  670. X    {
  671. X        cp = vp;
  672. X    }
  673. X    *(char **) ad->ad_valp = cp;
  674. X    return (TRUE);
  675. X}
  676. X
  677. XBOOL
  678. XargChar(ad, vp, copyf)
  679. X    register ARGDESC *ad;
  680. X    register char *vp;
  681. X    BOOL copyf;
  682. X{
  683. X    auto char *vpp;
  684. X    extern long strtol ARGS((char *, char **, int));
  685. X    int status = FALSE;
  686. X    char c;
  687. X
  688. X    if (strlen(vp) == 2 && vp[0]=='^')
  689. X    {
  690. X        c = vp[1] ^ '@';
  691. X        status = TRUE;
  692. X    }
  693. X    else if(strlen(vp) > 1 && vp[0]=='\\')
  694. X    {
  695. X        c = (int) strtol(&vp[1], &vpp, 8);
  696. X        if (*vpp == '\0')
  697. X            status = TRUE;
  698. X    }
  699. X    else if(strlen(vp) == 1)
  700. X    {
  701. X        c = *vp;
  702. X        status = TRUE;
  703. X    }
  704. X
  705. X    if(status == TRUE)
  706. X        *(char *) ad->ad_valp = c;
  707. X    else
  708. X    {
  709. X        usrerr("invalid character argument '%s' for %s",
  710. X            vp, ad->ad_prompt);
  711. X    }
  712. X    return status;
  713. X}
  714. X
  715. X/*ARGSUSED*/
  716. XBOOL
  717. XargInt(ad, vp, copyf)
  718. X    register ARGDESC *ad;
  719. X    register char *vp;
  720. X    BOOL copyf;
  721. X{
  722. X    auto char *vpp;
  723. X    extern long strtol ARGS((char *, char **, int));
  724. X
  725. X    *(int *) ad->ad_valp = (int) strtol(vp, &vpp, 0);
  726. X    if (*vpp != '\0')
  727. X    {
  728. X        usrerr("invalid integer argument '%s' for %s",
  729. X            vp, ad->ad_prompt);
  730. X        return (FALSE);
  731. X    }
  732. X    else
  733. X    {
  734. X        return (TRUE);
  735. X    }
  736. X}
  737. X
  738. X/*ARGSUSED*/
  739. XBOOL
  740. XargShort(ad, vp, copyf)
  741. X    register ARGDESC *ad;
  742. X    register char *vp;
  743. X    BOOL copyf;
  744. X{
  745. X    auto char *vpp;
  746. X    extern long strtol ARGS((char *, char **, int));
  747. X
  748. X    *(short *) ad->ad_valp = (short) strtol(vp, &vpp, 0);
  749. X    if (*vpp != '\0')
  750. X    {
  751. X        usrerr("invalid integer argument '%s' for %s",
  752. X            vp, ad->ad_prompt);
  753. X        return (FALSE);
  754. X    }
  755. X    else
  756. X    {
  757. X        return (TRUE);
  758. X    }
  759. X}
  760. X
  761. X/*ARGSUSED*/
  762. XBOOL
  763. XargLong(ad, vp, copyf)
  764. X    register ARGDESC *ad;
  765. X    register char *vp;
  766. X    BOOL copyf;
  767. X{
  768. X    auto char *vpp;
  769. X    extern long strtol ARGS((char *, char **, int));
  770. X
  771. X    *(long *) ad->ad_valp = strtol(vp, &vpp, 0);
  772. X    if (*vpp != '\0')
  773. X    {
  774. X        usrerr("invalid integer argument '%s' for %s",
  775. X            vp, ad->ad_prompt);
  776. X        return (FALSE);
  777. X    }
  778. X    else
  779. X    {
  780. X        return (TRUE);
  781. X    }
  782. X}
  783. X
  784. Xstruct booltab
  785. X{
  786. X    char    *bname;        /* string to match against */
  787. X    char    bneedmatch;    /* number of characters that must match */
  788. X    BOOL    bval;        /* value to use */
  789. X};
  790. X
  791. XSTATIC struct booltab    _BoolTab[] =
  792. X{
  793. X    "yes",        1,    TRUE,
  794. X    "no",        1,    FALSE,
  795. X    "true",        1,    TRUE,
  796. X    "false",    1,    FALSE,
  797. X    "on",        2,    TRUE,
  798. X    "off",        3,    FALSE,
  799. X    CHARNULL
  800. X};
  801. X
  802. X/*ARGSUSED*/
  803. XBOOL
  804. XargBool(ad, vp, copyf)
  805. X    register ARGDESC *ad;
  806. X    register char *vp;
  807. X    BOOL copyf;
  808. X{
  809. X    register struct booltab *b;
  810. X    register char *cp;
  811. X    int l;
  812. X
  813. X    /* convert input to lower case */
  814. X    for (l = 0, cp = vp; *cp != '\0'; l++, cp++)
  815. X    {
  816. X        if (isupper(*cp))
  817. X            *cp = tolower(*cp);
  818. X    }
  819. X
  820. X    /* search for a match in the table */
  821. X    for (b = _BoolTab; b->bname != CHARNULL; b++)
  822. X    {
  823. X        /* if too short, don't even bother trying */
  824. X        if (l < b->bneedmatch)
  825. X            continue;
  826. X
  827. X        if (bcmp(vp, b->bname, l) == 0)
  828. X        {
  829. X            /* got a match */
  830. X            *(BOOL *) ad->ad_valp = b->bval;
  831. X            return (TRUE);
  832. X        }
  833. X    }
  834. X
  835. X    usrerr("invalid Boolean argument '%s' for %s", vp, ad->ad_prompt);
  836. X    return (FALSE);
  837. X}
  838. X
  839. X#ifdef TRACESTUFF
  840. X/*ARGSUSED*/
  841. XBOOL
  842. XargTrace(ad, vp, copyf)
  843. X    register ARGDESC *ad;
  844. X    register char *vp;
  845. X    BOOL copyf;
  846. X{
  847. X    traceset(vp);
  848. X    return (TRUE);
  849. X}
  850. X#endif
  851. X
  852. X/*ARGSUSED*/
  853. XBOOL
  854. XargEnd(ad, vp, copyf)
  855. X    register ARGDESC *ad;
  856. X    register char *vp;
  857. X    BOOL copyf;
  858. X{
  859. X    return (FALSE);
  860. X}
  861. X
  862. XBOOL
  863. XargList(ad, vp, copyf)
  864. X    register ARGDESC *ad;
  865. X    register char *vp;
  866. X    BOOL copyf;
  867. X{
  868. X    char *cp;
  869. X    struct namelist *nl;
  870. X
  871. X    if (copyf)
  872. X    {
  873. X        register int i;
  874. X
  875. X        i = strlen(vp) + 1;
  876. X        cp = (char *) malloc(i);
  877. X        if(!cp) {
  878. X            usrerr("out of memory saving string %s", ad->ad_prompt);
  879. X            return FALSE;
  880. X        }
  881. X        bcopy(vp, cp, i);
  882. X    }
  883. X    else
  884. X    {
  885. X        cp = vp;
  886. X    }
  887. X
  888. X    nl = (struct namelist *) malloc(sizeof *nl);
  889. X    if(!nl) {
  890. X        usrerr("out of memory saving arg %s", ad->ad_prompt);
  891. X        if(copyf) free(cp);
  892. X        return FALSE;
  893. X    }
  894. X
  895. X    nl->nl_next = *(struct namelist **) ad->ad_valp;
  896. X    nl->nl_name = cp;
  897. X    *(struct namelist **) ad->ad_valp = nl;
  898. X    return (TRUE);
  899. X}
  900. //END_OF_FILE
  901. echo x - fp_argtype.c
  902. sed 's/^X//' > fp_argtype.c << '//END_OF_FILE'
  903. X#include <useful.h>
  904. X#include <parseargs.h>
  905. X
  906. XVERSIONID("$Header: fp_args.c,v 2.0 89/12/24 00:56:21 eric Exp $");
  907. X
  908. X/*
  909. X**  PARSEARGV argument type functions for floating point operands.
  910. X**
  911. X**    These are broken out to avoid loading the floating precision
  912. X**    conversion routines when they aren't actually needed.
  913. X**
  914. X**    Author:
  915. X**        Eric Allman
  916. X**        University of California, Berkeley
  917. X*/
  918. X
  919. X/*ARGSUSED*/
  920. XBOOL
  921. XargDouble(ad, vp, copyf)
  922. X    register ARGDESC *ad;
  923. X    register char *vp;
  924. X    BOOL copyf;
  925. X{
  926. X    auto char *vpp;
  927. X    extern double strtod ARGS((char *, char **));
  928. X
  929. X    *(double *) ad->ad_valp = strtod(vp, &vpp);
  930. X    if (*vpp != '\0')
  931. X    {
  932. X        usrerr("invalid floating point argument '%s' for %s",
  933. X            vp, ad->ad_prompt);
  934. X        return (FALSE);
  935. X    }
  936. X    else
  937. X    {
  938. X        return (TRUE);
  939. X    }
  940. X}
  941. X
  942. X/*ARGSUSED*/
  943. XBOOL
  944. XargFloat(ad, vp, copyf)
  945. X    register ARGDESC *ad;
  946. X    register char *vp;
  947. X    BOOL copyf;
  948. X{
  949. X    auto char *vpp;
  950. X    extern double strtod ARGS((char *, char **));
  951. X
  952. X    *(float *) ad->ad_valp = (float) strtod(vp, &vpp);
  953. X    if (*vpp != '\0')
  954. X    {
  955. X        usrerr("invalid floating point argument '%s' for %s",
  956. X            vp, ad->ad_prompt);
  957. X        return (FALSE);
  958. X    }
  959. X    else
  960. X    {
  961. X        return (TRUE);
  962. X    }
  963. X}
  964. //END_OF_FILE
  965. echo x - funclist.c
  966. sed 's/^X//' > funclist.c << '//END_OF_FILE'
  967. X#include <useful.h>
  968. X#include <funclist.h>
  969. X
  970. XVERSIONID("$Header: funclist.c,v 2.0 89/12/24 00:56:22 eric Exp $");
  971. X
  972. X/*
  973. X**  FUNCLIST_ADD -- add a function specification to a function list
  974. X**
  975. X**    Parameters:
  976. X**        flh -- the address of a pointer to a function list.  Note
  977. X**            that this must be a FUNCLIST **.
  978. X**        func -- the function to add to the list.
  979. X**        arg -- the first argument to the function.
  980. X**
  981. X**    Returns:
  982. X**        none.
  983. X**
  984. X**    Side Effects:
  985. X**        The indicated function is added to the function list
  986. X**        for later invocation by funclist_call.
  987. X**
  988. X**    Author:
  989. X**        Eric Allman
  990. X**        University of California, Berkeley
  991. X*/
  992. X
  993. XVOID
  994. Xfunclist_add(flh, func, arg)
  995. X    FUNCLIST **flh;
  996. X    VOID (*func)();
  997. X    ARBPTR arg;
  998. X{
  999. X    register FUNCLIST *fl;
  1000. X
  1001. X    fl = (FUNCLIST *) ckalloc(sizeof *fl);
  1002. X    fl->_fl_func = func;
  1003. X    fl->_fl_arg = arg;
  1004. X    fl->_fl_next = *flh;
  1005. X    *flh = fl;
  1006. X}
  1007. X /*
  1008. X**  FUNCLIST_CALL -- call all the functions on a function list.
  1009. X**
  1010. X**    Parameters:
  1011. X**        fl -- the function list to call.  Unlike funclist_add,
  1012. X**            this should not be an indirect pointer.
  1013. X**        arg -- the second argument to the functions.
  1014. X**
  1015. X**    Returns:
  1016. X**        none.
  1017. X**
  1018. X**    Side Effects:
  1019. X**        As implied by the function list.
  1020. X*/
  1021. X
  1022. XVOID
  1023. Xfunclist_call(fl, arg)
  1024. X    register FUNCLIST *fl;
  1025. X    ARBPTR arg;
  1026. X{
  1027. X    while (fl != FUNCLISTNULL)
  1028. X    {
  1029. X        (*fl->_fl_func)(fl->_fl_arg, arg);
  1030. X        fl = fl->_fl_next;
  1031. X    }
  1032. X}
  1033. //END_OF_FILE
  1034. echo x - openpath.c
  1035. sed 's/^X//' > openpath.c << '//END_OF_FILE'
  1036. X#include <useful.h>
  1037. X
  1038. XVERSIONID("$Header: openpath.c,v 2.0 89/12/24 00:56:26 eric Exp $");
  1039. X
  1040. X/*
  1041. X**  OPENPATH -- open a file, searching through a path
  1042. X**
  1043. X**    Parameters:
  1044. X**        fname -- the file name, relative to the desired path.
  1045. X**        mode -- the open mode, just like fopen.
  1046. X**        path -- the search path.
  1047. X**
  1048. X**    Returns:
  1049. X**        FILENULL if the file could not be found at all.
  1050. X**        A FILE pointer open for reading for the first instance
  1051. X**            of the file that could be found in the path
  1052. X**            otherwise.
  1053. X**
  1054. X**    Side Effects:
  1055. X**        none.
  1056. X**
  1057. X**    Notes:
  1058. X**        Should really just find the file, not open it.
  1059. X**
  1060. X**    Author:
  1061. X**        Eric Allman
  1062. X**        University of California, Berkeley
  1063. X*/
  1064. X
  1065. Xchar    *DefaultPath =        CHARNULL;
  1066. X
  1067. X#ifndef DEFAULTROOTPATH
  1068. X#define DEFAULTROOTPATH        "/usr/local:/usr:~:"
  1069. X#endif
  1070. X
  1071. XFILE *
  1072. Xopenpath(fname, mode, path)
  1073. X    char *fname;
  1074. X    char *mode;
  1075. X    char *path;
  1076. X{
  1077. X    register char *dp;
  1078. X    register char *ep;
  1079. X    register char *bp;
  1080. X    FILE *fp;
  1081. X    char fbuf[200];
  1082. X    extern char *getenv ARGS((char *));
  1083. X
  1084. X    dp = path;
  1085. X    if (dp == CHARNULL)
  1086. X    {
  1087. X        dp = DefaultPath;
  1088. X        if (dp == CHARNULL)
  1089. X        {
  1090. X            /* locate the root of our utility tree */
  1091. X            dp = getenv("ROOTPATH");
  1092. X            if (dp == CHARNULL)
  1093. X                dp = DEFAULTROOTPATH;
  1094. X            DefaultPath = dp;
  1095. X        }
  1096. X    }
  1097. X    for (;; dp = ++ep)
  1098. X    {
  1099. X        register int l;
  1100. X        int i;
  1101. X        int fspace;
  1102. X
  1103. X        /* extract a component */
  1104. X        ep = strchr(dp, ':');
  1105. X        if (ep == CHARNULL)
  1106. X            ep = &dp[strlen(dp)];
  1107. X
  1108. X        /* find the length of that component */
  1109. X        l = ep - dp;
  1110. X        bp = fbuf;
  1111. X        fspace = sizeof fbuf - 2;
  1112. X        if (l > 0)
  1113. X        {
  1114. X            /*
  1115. X            **  If the length of the component is zero length,
  1116. X            **  start from the current directory.  If the
  1117. X            **  component begins with "~", start from the
  1118. X            **  user's $HOME environment variable.  Otherwise
  1119. X            **  take the path literally.
  1120. X            */
  1121. X
  1122. X            if (*dp == '~' && (l == 1 || dp[1] == '/'))
  1123. X            {
  1124. X                char *home;
  1125. X
  1126. X                home = getenv("HOME");
  1127. X                if (home != CHARNULL)
  1128. X                {
  1129. X                    i = strlen(home);
  1130. X                    if ((fspace -= i) < 0)
  1131. X                        goto toolong;
  1132. X                    bcopy(home, bp, i);
  1133. X                    bp += i;
  1134. X                }
  1135. X                dp++;
  1136. X                l--;
  1137. X            }
  1138. X            if (l > 0)
  1139. X            {
  1140. X                if ((fspace -= l) < 0)
  1141. X                    goto toolong;
  1142. X                bcopy(dp, bp, l);
  1143. X                bp += l;
  1144. X            }
  1145. X
  1146. X            /* add a "/" between directory and filename */
  1147. X            if (ep[-1] != '/')
  1148. X                *bp++ = '/';
  1149. X        }
  1150. X
  1151. X        /* now append the file name */
  1152. X        i = strlen(fname);
  1153. X        if ((fspace -= i) < 0)
  1154. X        {
  1155. X    toolong:
  1156. X            fprintf(stderr, "openpath: pathname too long (ignored)\n");
  1157. X            *bp = '\0';
  1158. X            fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
  1159. X            fprintf(stderr, "\tFile \"%s\"\n", fname);
  1160. X            continue;
  1161. X        }
  1162. X        bcopy(fname, bp, i + 1);
  1163. X
  1164. X        /* try to open that file */
  1165. X        fp = fopen(fbuf, mode);
  1166. X
  1167. X        /* if it exists, all is well */
  1168. X        if (fp != FILENULL)
  1169. X            return (fp);
  1170. X
  1171. X        /* if not, and no other alternatives, life is bleak */
  1172. X        if (*ep == '\0')
  1173. X            return (FILENULL);
  1174. X
  1175. X        /* otherwise try the next component in the search path */
  1176. X    }
  1177. X}
  1178. //END_OF_FILE
  1179. echo x - amiga_args.c
  1180. sed 's/^X//' > amiga_args.c << '//END_OF_FILE'
  1181. X#include <useful.h>
  1182. X#include <parseargs.h>
  1183. X#include <ctype.h>
  1184. X
  1185. XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  1186. X
  1187. X/*
  1188. X**  PARSEARGS -- parse an argument vector, given a description
  1189. X**
  1190. X**    Parameters:
  1191. X**        argv -- the argument vector as passed to main().
  1192. X**        argd -- the argument descriptor array.
  1193. X**
  1194. X**    Returns:
  1195. X**        Nothing
  1196. X**            Exits with return code 20 if error in args.
  1197. X**            Exits with return code 10 if system error.
  1198. X**
  1199. X**    Side Effects:
  1200. X**        Converts and stores arguments into variables as
  1201. X**        described by argd.
  1202. X**
  1203. X**    Globals:
  1204. X**        DefaultPath -- the pathname of a set of places to
  1205. X**            look for system files, set from the ROOTPATH
  1206. X**            environment variable, or a default.
  1207. X**        ProgName -- the name of this program, saved for error
  1208. X**            messages and the like.
  1209. X**
  1210. X**    Author:
  1211. X**        Eric Allman
  1212. X**        University of California, Berkeley
  1213. X*/
  1214. X
  1215. X#define ALL_AD        ad = argd; ad->ad_name != '\0'; ad++
  1216. X#define ALL_DEFS    ad = _DefaultArgs; ad->ad_name != '\0'; ad++
  1217. X
  1218. Xchar    *ProgName;
  1219. X
  1220. X#ifdef TRACESTUFF
  1221. Xextern BOOL    argTrace ARGS((ARGDESC *, char *, BOOL));
  1222. X#endif
  1223. Xextern BOOL    argEnd ARGS((ARGDESC *, char *, BOOL));
  1224. X
  1225. X/* default arguments -- apply to all programs */
  1226. XSTATIC ARGDESC    _DefaultArgs[] =
  1227. X{
  1228. X     /* name    flags    type        valp        prompt        */
  1229. X#ifdef TRACESTUFF
  1230. X    'T',    ARGOPT,    argTrace,    ARBNULL,    "TRACE",
  1231. X#endif
  1232. X    '-',    ARGOPT,    argEnd,        ARBNULL,    "ARGS",
  1233. X    ENDOFARGS
  1234. X};
  1235. X
  1236. X/* override argument descriptor, if none given by user */
  1237. XSTATIC ARGDESC    _NullArgDesc[] =
  1238. X{
  1239. X    ENDOFARGS
  1240. X};
  1241. X
  1242. XVOID
  1243. Xparseargs(argv, argd)
  1244. X    char **argv;
  1245. X    ARGDESC argd[];
  1246. X{
  1247. X    register ARGDESC *ad, *list;
  1248. X    register char **av;
  1249. X    register char *p;
  1250. X    BOOL noflags;
  1251. X    BOOL error;
  1252. X    extern char *getenv ARGS((char *));
  1253. X
  1254. X    av = argv++;
  1255. X    /* save the name of this program (for error messages) */
  1256. X    ProgName = *av;
  1257. X
  1258. X    /* allow null argument descriptor */
  1259. X    if (argd == (ARGDESC *) NULL)
  1260. X        argd = _NullArgDesc;
  1261. X
  1262. X    /* clear out any cruft in the argument descriptor */
  1263. X    for (ALL_AD)
  1264. X    {
  1265. X        ad->ad_flags &= ~ARGGIVEN;
  1266. X    }
  1267. X    for (ALL_DEFS)
  1268. X    {
  1269. X        ad->ad_flags &= ~ARGGIVEN;
  1270. X    }
  1271. X
  1272. X    /* run through the argument vector */
  1273. X    noflags = FALSE;
  1274. X    error = FALSE;
  1275. X    ad = NULL; /* No argument requested */
  1276. X    list = NULL;
  1277. X    while (*++av != CHARNULL)
  1278. X    {
  1279. X        /* Previous keyword required a value */
  1280. X        if(ad)
  1281. X        {
  1282. X            /* try to convert the type */
  1283. X            if (!(*ad->ad_type)(ad, *av, FALSE))
  1284. X                error = TRUE;
  1285. X            else
  1286. X                ad->ad_flags |= ARGGIVEN;
  1287. X            ad = NULL;
  1288. X            continue;
  1289. X        }
  1290. X        
  1291. X        /* If looking for keywords, see if this is one */
  1292. X        if(!noflags) {
  1293. X            for(ALL_AD)
  1294. X                if(match(*av, ad->ad_prompt) == 0)
  1295. X                    break;
  1296. X            if(ad->ad_name == '\0')
  1297. X                for(ALL_DEFS)
  1298. X                    if(match(*av, ad->ad_prompt) == 0)
  1299. X                        break;
  1300. X        }
  1301. X        if(ad->ad_name == '\0')
  1302. X            ad = NULL;
  1303. X
  1304. X        /* If we have a keyword here */
  1305. X        if(!noflags && ad)
  1306. X        {
  1307. X            list = NULL;
  1308. X            p = strchr(*av, '=');
  1309. X            if(p) /* matched NAME=VALUE */
  1310. X            {
  1311. X                p++;
  1312. X                /* try to convert the type */
  1313. X                if (!(*ad->ad_type)(ad, p, FALSE))
  1314. X                    error = TRUE;
  1315. X                else
  1316. X                    ad->ad_flags |= ARGGIVEN;
  1317. X                ad = NULL;
  1318. X            }
  1319. X            else
  1320. X            {
  1321. X                if (ad->ad_type == argBool)
  1322. X                {
  1323. X                    *(BOOL *) ad->ad_valp = TRUE;
  1324. X                    ad->ad_flags |= ARGGIVEN;
  1325. X                    ad = NULL;
  1326. X                }
  1327. X                else if (ad->ad_type == argEnd)
  1328. X                {
  1329. X                    noflags = TRUE;
  1330. X                    ad->ad_flags |= ARGGIVEN;
  1331. X                    ad = NULL;
  1332. X                }
  1333. X                else if (ad->ad_type == argList)
  1334. X                {
  1335. X                    list = ad;
  1336. X                    ad = NULL;
  1337. X                }
  1338. X            }
  1339. X        }
  1340. X        else /* it's a positional argument */
  1341. X        {
  1342. X            if(list) {
  1343. X                if (!argList(list, *av, FALSE))
  1344. X                    error = TRUE;
  1345. X                list->ad_flags |= ARGGIVEN;
  1346. X                continue;
  1347. X            }
  1348. X            else
  1349. X            {
  1350. X                for (ALL_AD)
  1351. X                {
  1352. X                    if (ad->ad_name == ' ' &&
  1353. X                        (ad->ad_type == argList ||
  1354. X                         !BITSET(ARGGIVEN, ad->ad_flags))
  1355. X                       )
  1356. X                        break;
  1357. X                }
  1358. X                if (ad->ad_name == '\0')
  1359. X                {
  1360. X                    usrerr("too any arguments");
  1361. X                    error = TRUE;
  1362. X                    ad = NULL;
  1363. X                }
  1364. X                else
  1365. X                {
  1366. X                    /* try to convert */
  1367. X                    if (!(*ad->ad_type)(ad, *av, FALSE))
  1368. X                        error = TRUE;
  1369. X                    else
  1370. X                        ad->ad_flags |= ARGGIVEN;
  1371. X                    ad = NULL;
  1372. X                }
  1373. X            }
  1374. X        }
  1375. X    }
  1376. X
  1377. X    /* If last argument was a keyword and required an option
  1378. X     * then complain about it
  1379. X     */
  1380. X    if(ad) {
  1381. X        usrerr("missing argument for %s", ad->ad_prompt);
  1382. X        error = TRUE;
  1383. X    }
  1384. X    *argv = NULL;
  1385. X
  1386. X    /* now rescan for missing required arguments */
  1387. X    for (ALL_AD)
  1388. X    {
  1389. X        if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
  1390. X        {
  1391. X            if (!BITSET(ARGGIVEN, ad->ad_flags))
  1392. X            {
  1393. X                /* still didn't get a value... sigh */
  1394. X                if (ad->ad_name == ' ')
  1395. X                {
  1396. X                    usrerr("%s required",
  1397. X                        ad->ad_prompt);
  1398. X                }
  1399. X                else
  1400. X                {
  1401. X                    usrerr("%s required for -%c flag",
  1402. X                        ad->ad_prompt, ad->ad_name);
  1403. X                }
  1404. X                error = TRUE;
  1405. X            }
  1406. X        }
  1407. X    }
  1408. X
  1409. X    if (error)
  1410. X    {
  1411. X        usage(argd);
  1412. X        exit(20);
  1413. X    }
  1414. X}
  1415. X /*
  1416. X**  USAGE -- print a usage message
  1417. X**
  1418. X**    Parameters:
  1419. X**        argd -- the description of expected arguments.
  1420. X**
  1421. X**    Returns:
  1422. X**        none
  1423. X**
  1424. X**    Side Effects:
  1425. X**        prints on stderr
  1426. X**
  1427. X**    Globals:
  1428. X**        MaxOutputLine -- the length of the maximum output line
  1429. X**            allowed before wrapping.  This should be fetched
  1430. X**            from the terminal driver on systems that support
  1431. X**            this sort of thing.
  1432. X*/
  1433. X
  1434. Xint    MaxOutputLine = 72;
  1435. X
  1436. XVOID
  1437. Xusage(argd)
  1438. X    ARGDESC *argd;
  1439. X{
  1440. X    register ARGDESC *ad;
  1441. X    int ll;
  1442. X    int pl;
  1443. X
  1444. X    fprintf(stderr, "Usage: %s", ProgName);
  1445. X    ll = strlen(ProgName) + 7;
  1446. X
  1447. X    for (ALL_AD)
  1448. X    {
  1449. X        char keyword[BUFSIZ];
  1450. X        char name[BUFSIZ];
  1451. X        int i, j;
  1452. X
  1453. X        j = 0;
  1454. X        for(i = 0; ad->ad_prompt[i]; i++) {
  1455. X            if(isupper(ad->ad_prompt[i])) {
  1456. X                keyword[j++] = ad->ad_prompt[i];
  1457. X                name[i] = tolower(ad->ad_prompt[i]);
  1458. X            }
  1459. X            else
  1460. X                name[i] = ad->ad_prompt[i];
  1461. X        }
  1462. X        name[i] = 0;
  1463. X        if(j > 0)
  1464. X            keyword[j] = 0;
  1465. X        else
  1466. X            strcpy(keyword, ad->ad_prompt);
  1467. X
  1468. X        /* don't display hidden arguments */
  1469. X        if (BITSET(ARGHIDDEN, ad->ad_flags))
  1470. X            continue;
  1471. X
  1472. X        /* figure out how wide this parameter is (for printing) */
  1473. X        if (ad->ad_name != ' ')
  1474. X        {
  1475. X            pl = strlen(keyword);
  1476. X            if (ad->ad_type != argBool)
  1477. X                pl += strlen(name) + 3;/* _< > */
  1478. X        }
  1479. X        else
  1480. X        {
  1481. X            pl = strlen(name) + 2;        /* < > */
  1482. X        }
  1483. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1484. X            pl += 2;                /* [ ] */
  1485. X        if (ad->ad_type == argList)
  1486. X            pl += 3;            /* ... */
  1487. X        pl += 1;                    /* leading sp */
  1488. X
  1489. X        /* see if this will fit */
  1490. X        if (ll + pl > MaxOutputLine)
  1491. X        {
  1492. X            /* no... start a new line */
  1493. X            fprintf(stderr, " +\n\t");
  1494. X            ll = 7;
  1495. X        }
  1496. X        else
  1497. X        {
  1498. X            /* yes... just throw in a space */
  1499. X            fprintf(stderr, " ");
  1500. X        }
  1501. X        ll += pl;
  1502. X
  1503. X        /* show the argument */
  1504. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1505. X            fprintf(stderr, "[");
  1506. X        if (ad->ad_name != ' ')
  1507. X        {
  1508. X            fprintf(stderr, "%s", keyword);
  1509. X            if (ad->ad_type != argBool)
  1510. X                fprintf(stderr, " ");
  1511. X        }
  1512. X        if (ad->ad_name == ' ' || ad->ad_type != argBool)
  1513. X            fprintf(stderr, "<%s>", name);
  1514. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1515. X            fprintf(stderr, "]");
  1516. X        if (ad->ad_type == argList)
  1517. X            fprintf(stderr, "...");
  1518. X    }
  1519. X    fprintf(stderr, "\n");
  1520. X}
  1521. X
  1522. X /* match(s1, s2)
  1523. X**
  1524. X** Compares two strings, returning >0, <0, or =0 if they match. First a
  1525. X** check is done on letters capitalised in the second word, and if this
  1526. X** fails then a complete match is done. Case is ignored in both matches.
  1527. X** This lets you use case to indicate what part of a keyword is significant.
  1528. X*/
  1529. Xint match(candidate, target)
  1530. Xchar *target, *candidate;
  1531. X{
  1532. X    int i, j;
  1533. X    char c;
  1534. X
  1535. X    i = j = 0;
  1536. X
  1537. X    while(target[i] || candidate[i]) {
  1538. X        while(islower(target[i])) i++;
  1539. X        if(!target[i]) {
  1540. X            if(!candidate[j]) return 0;
  1541. X            return dictcmp(target, candidate);
  1542. X        }
  1543. X        c = islower(candidate[j])
  1544. X            ? toupper(candidate[j])
  1545. X            : candidate[j];
  1546. X        if(target[i] != c) return dictcmp(target, candidate);
  1547. X        i++;
  1548. X        j++;
  1549. X    }
  1550. X    return 0;
  1551. X}
  1552. X
  1553. Xint dictcmp(s1, s2)    /* "Dictionary" comparison of two strings */
  1554. Xchar *s1, *s2;
  1555. X{
  1556. X    char c1, c2;
  1557. X
  1558. X    while(*s1 || *s2) {
  1559. X        c1 = *s1++;
  1560. X        c2 = *s2++;
  1561. X        if(!c1 || !c2) return c1 - c2;
  1562. X        if(isupper(c1)) c1 = tolower(c1);
  1563. X        if(isupper(c2)) c2 = tolower(c2);
  1564. X        if(c1 != c2) return c1 - c2;
  1565. X    }
  1566. X    return 0;
  1567. X}
  1568. //END_OF_FILE
  1569. echo x - unix_args.c
  1570. sed 's/^X//' > unix_args.c << '//END_OF_FILE'
  1571. X#include <useful.h>
  1572. X#include <parseargs.h>
  1573. X#include <ctype.h>
  1574. X
  1575. XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  1576. X
  1577. X/*
  1578. X**  PARSEARGS -- parse an argument vector, given a description
  1579. X**
  1580. X**    Parameters:
  1581. X**        argv -- pointer to the argument vector as passed to main().
  1582. X**        argd -- the argument descriptor array.
  1583. X**
  1584. X**    Returns:
  1585. X**        Nothing.
  1586. X**            Exits with return code 2 if error in args.
  1587. X**            Exits with return code 1 if system error.
  1588. X**
  1589. X**    Side Effects:
  1590. X**        Converts and stores arguments into variables as
  1591. X**        described by argd.
  1592. X**
  1593. X**    Globals:
  1594. X**        DefaultPath -- the pathname of a set of places to
  1595. X**            look for system files, set from the ROOTPATH
  1596. X**            environment variable, or a default.
  1597. X**        ProgName -- the name of this program, saved for error
  1598. X**            messages and the like.
  1599. X**
  1600. X**    Author:
  1601. X**        Eric Allman
  1602. X**        University of California, Berkeley
  1603. X*/
  1604. X
  1605. X#define ALL_AD        ad = argd; ad->ad_name != '\0'; ad++
  1606. X#define ALL_DEFS    ad = _DefaultArgs; ad->ad_name != '\0'; ad++
  1607. X
  1608. Xchar    *ProgName;
  1609. X
  1610. X#ifdef TRACESTUFF
  1611. Xextern BOOL    argTrace ARGS((ARGDESC *, char *, BOOL));
  1612. X#endif
  1613. Xextern BOOL    argEnd ARGS((ARGDESC *, char *, BOOL));
  1614. X
  1615. X/* default arguments -- apply to all programs */
  1616. XSTATIC ARGDESC    _DefaultArgs[] =
  1617. X{
  1618. X     /* name    flags    type        valp        prompt        */
  1619. X#ifdef TRACESTUFF
  1620. X    'T',    ARGOPT,    argTrace,    ARBNULL,    "TRACE",
  1621. X#endif
  1622. X    '-',    ARGOPT,    argEnd,        ARBNULL,    "ARGS",
  1623. X    ENDOFARGS
  1624. X};
  1625. X
  1626. X/* override argument descriptor, if none given by user */
  1627. XSTATIC ARGDESC    _NullArgDesc[] =
  1628. X{
  1629. X    ENDOFARGS
  1630. X};
  1631. X
  1632. XVOID
  1633. Xparseargs(argv, argd)
  1634. X    char **argv;
  1635. X    ARGDESC argd[];
  1636. X{
  1637. X    register ARGDESC *ad, *list;
  1638. X    register char **av;
  1639. X    register char *p;
  1640. X    int argc;
  1641. X    BOOL noflags;
  1642. X    BOOL error;
  1643. X#ifdef INTERACTIVE
  1644. X    BOOL shouldprompt;
  1645. X#endif
  1646. X    extern char *getenv ARGS((char *));
  1647. X#ifdef INTERACTIVE
  1648. X    extern int isatty ARGS((int));
  1649. X#endif
  1650. X
  1651. X    av = argv++;
  1652. X    argc = 1;
  1653. X
  1654. X    /* save the name of this program (for error messages) */
  1655. X    ProgName = *av;
  1656. X
  1657. X#ifdef INTERACTIVE
  1658. X    /* test to see if we are interactive */
  1659. X    shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
  1660. X#endif
  1661. X
  1662. X    /* allow null argument descriptor */
  1663. X    if (argd == (ARGDESC *) NULL)
  1664. X        argd = _NullArgDesc;
  1665. X
  1666. X    /* clear out any cruft in the argument descriptor */
  1667. X    for (ALL_AD)
  1668. X    {
  1669. X        ad->ad_flags &= ~ARGGIVEN;
  1670. X    }
  1671. X    for (ALL_DEFS)
  1672. X    {
  1673. X        ad->ad_flags &= ~ARGGIVEN;
  1674. X    }
  1675. X
  1676. X    /* run through the argument vector */
  1677. X    noflags = FALSE;
  1678. X    error = FALSE;
  1679. X    list = NULL;
  1680. X    while ((p = *++av) != CHARNULL)
  1681. X    {
  1682. X        if (*p == '-' && !noflags)
  1683. X        {
  1684. X            /* flag argument */
  1685. X            if (*++p == '-' && p[1] == '\0')
  1686. X            {
  1687. X                /* -- indicates end of flags */
  1688. X                noflags = TRUE;
  1689. X                list = NULL;
  1690. X                continue;
  1691. X            }
  1692. X            while (*p != '\0')
  1693. X            {
  1694. X                /* find the flag in the list */
  1695. X                for (ALL_AD)
  1696. X                {
  1697. X                    if (ad->ad_name == *p)
  1698. X                        break;
  1699. X                }
  1700. X                if (ad->ad_name == '\0')
  1701. X                {
  1702. X                    for (ALL_DEFS)
  1703. X                    {
  1704. X                        if (ad->ad_name == *p)
  1705. X                            break;
  1706. X                    }
  1707. X                    if (ad->ad_name == '\0')
  1708. X                    {
  1709. X                        usrerr("flag -%c unknown", *p++);
  1710. X                        error = TRUE;
  1711. X                        continue;
  1712. X                    }
  1713. X                }
  1714. X
  1715. X                /* move p up to point to the (possible) value */
  1716. X                p++;
  1717. X
  1718. X                /* booleans are special, having no value */
  1719. X                if (ad->ad_type == argBool)
  1720. X                {
  1721. X                    *(BOOL *) ad->ad_valp = TRUE;
  1722. X                    ad->ad_flags |= ARGGIVEN;
  1723. X                    continue;
  1724. X                }
  1725. X#ifdef TRACESTUFF
  1726. X                else if (ad->ad_type == argTrace)
  1727. X                {
  1728. X                    traceset(p);
  1729. X                    ad->ad_flags |= ARGGIVEN;
  1730. X                    break;
  1731. X                }
  1732. X#endif
  1733. X
  1734. X                /* now get the real value */
  1735. X                if (*p == '\0')
  1736. X                {
  1737. X                    p = *++av;
  1738. X                    if (p == CHARNULL || *p == '-')
  1739. X                    {
  1740. X                        av--;
  1741. X                        usrerr("%s required for -%c flag",
  1742. X                            ad->ad_prompt, ad->ad_name);
  1743. X                        error = TRUE;
  1744. X                        break;
  1745. X                    }
  1746. X                }
  1747. X
  1748. X                /* try to convert the type */
  1749. X                if (!(*ad->ad_type)(ad, p, FALSE))
  1750. X                    error = TRUE;
  1751. X                else
  1752. X                    ad->ad_flags |= ARGGIVEN;
  1753. X                if(ad->ad_type == argList)
  1754. X                    list = ad;
  1755. X                else
  1756. X                    list = NULL;
  1757. X                break;
  1758. X            }
  1759. X        }
  1760. X        else
  1761. X        {
  1762. X            /* parsing a list of arguments */
  1763. X            if(list) {
  1764. X                if (!argList(list, p, FALSE))
  1765. X                    error = TRUE;
  1766. X                continue;
  1767. X            }
  1768. X            /* positional argument */
  1769. X            for (ALL_AD)
  1770. X            {
  1771. X                if (ad->ad_name == ' ' &&
  1772. X                    (ad->ad_type == argList ||
  1773. X                     !BITSET(ARGGIVEN, ad->ad_flags))
  1774. X                    )
  1775. X                    break;
  1776. X            }
  1777. X            if (ad->ad_name == '\0')
  1778. X            {
  1779. X                usrerr("too any arguments");
  1780. X                error = 1;
  1781. X                continue;
  1782. X            }
  1783. X
  1784. X            /* try to convert */
  1785. X            if (!(*ad->ad_type)(ad, p, FALSE))
  1786. X                error = TRUE;
  1787. X            else
  1788. X                ad->ad_flags |= ARGGIVEN;
  1789. X        }
  1790. X    }
  1791. X
  1792. X    /* now rescan for missing required arguments */
  1793. X    for (ALL_AD)
  1794. X    {
  1795. X        if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
  1796. X        {
  1797. X#ifdef INTERACTIVE
  1798. X            /* can we prompt? */
  1799. X            while (shouldprompt && !error)
  1800. X            {
  1801. X                char buf[MAXINPUTLINE];
  1802. X
  1803. X                fprintf(stderr, "%s? ", ad->ad_prompt);
  1804. X                fflush(stderr);
  1805. X                if (fgets(buf, sizeof buf, stdin) == CHARNULL)
  1806. X                    break;
  1807. X                p = strchr(buf, '\n');
  1808. X                if (p != CHARNULL)
  1809. X                    *p = '\0';
  1810. X                if (buf[0] == '\0')
  1811. X                {
  1812. X                    usrerr("value required");
  1813. X                    continue;
  1814. X                }
  1815. X                if ((*ad->ad_type)(ad, buf, TRUE))
  1816. X                {
  1817. X                    ad->ad_flags |= ARGGIVEN;
  1818. X                    break;
  1819. X                }
  1820. X            }
  1821. X#endif
  1822. X
  1823. X            if (!BITSET(ARGGIVEN, ad->ad_flags))
  1824. X            {
  1825. X                /* still didn't get a value... sigh */
  1826. X                if (ad->ad_name == ' ')
  1827. X                {
  1828. X                    usrerr("%s required",
  1829. X                        ad->ad_prompt);
  1830. X                }
  1831. X                else
  1832. X                {
  1833. X                    usrerr("%s required for -%c flag",
  1834. X                        ad->ad_prompt, ad->ad_name);
  1835. X                }
  1836. X                error = TRUE;
  1837. X            }
  1838. X        }
  1839. X    }
  1840. X
  1841. X    if (error)
  1842. X    {
  1843. X        usage(argd);
  1844. X        exit(2);
  1845. X    }
  1846. X
  1847. X    return argc;
  1848. X}
  1849. X /*
  1850. X**  USAGE -- print a usage message
  1851. X**
  1852. X**    Parameters:
  1853. X**        argd -- the description of expected arguments.
  1854. X**
  1855. X**    Returns:
  1856. X**        none
  1857. X**
  1858. X**    Side Effects:
  1859. X**        prints on stderr
  1860. X**
  1861. X**    Globals:
  1862. X**        MaxOutputLine -- the length of the maximum output line
  1863. X**            allowed before wrapping.  This should be fetched
  1864. X**            from the terminal driver on systems that support
  1865. X**            this sort of thing.
  1866. X*/
  1867. X
  1868. Xint    MaxOutputLine = 72;
  1869. X
  1870. XVOID
  1871. Xusage(argd)
  1872. X    ARGDESC *argd;
  1873. X{
  1874. X    register ARGDESC *ad;
  1875. X    int ll;
  1876. X    int pl;
  1877. X
  1878. X    fprintf(stderr, "Usage: %s", ProgName);
  1879. X    ll = strlen(ProgName) + 7;
  1880. X
  1881. X    for (ALL_AD)
  1882. X    {
  1883. X        /* don't display hidden arguments */
  1884. X        if (BITSET(ARGHIDDEN, ad->ad_flags))
  1885. X            continue;
  1886. X
  1887. X        /* figure out how wide this parameter is (for printing) */
  1888. X        if (ad->ad_name != ' ')
  1889. X        {
  1890. X            pl = 2;                    /* -x */
  1891. X            if (ad->ad_type != argBool)
  1892. X                pl += strlen(ad->ad_prompt) + 3;/* _< > */
  1893. X        }
  1894. X        else
  1895. X        {
  1896. X            pl = strlen(ad->ad_prompt) + 2;        /* < > */
  1897. X        }
  1898. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1899. X            pl += 2;                /* [ ] */
  1900. X        if (ad->ad_type == argList)            /* ... */
  1901. X            pl += 3;
  1902. X        pl += 1;                    /* leading sp */
  1903. X
  1904. X        /* see if this will fit */
  1905. X        if (ll + pl > MaxOutputLine)
  1906. X        {
  1907. X            /* no... start a new line */
  1908. X            fprintf(stderr, " \\\n\t");
  1909. X            ll = 7;
  1910. X        }
  1911. X        else
  1912. X        {
  1913. X            /* yes... just throw in a space */
  1914. X            fprintf(stderr, " ");
  1915. X        }
  1916. X        ll += pl;
  1917. X
  1918. X        /* show the argument */
  1919. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1920. X            fprintf(stderr, "[");
  1921. X        if (ad->ad_name != ' ')
  1922. X        {
  1923. X            fprintf(stderr, "-%c", ad->ad_name);
  1924. X            if (ad->ad_type != argBool)
  1925. X                fprintf(stderr, " ");
  1926. X        }
  1927. X        if (ad->ad_name == ' ' || ad->ad_type != argBool)
  1928. X            fprintf(stderr, "<%s>", ad->ad_prompt);
  1929. X        if (!BITSET(ARGREQ, ad->ad_flags))
  1930. X            fprintf(stderr, "]");
  1931. X        if (ad->ad_type == argList)
  1932. X            fprintf(stderr, "...");
  1933. X    }
  1934. X    fprintf(stderr, "\n");
  1935. X}
  1936. //END_OF_FILE
  1937. echo x - syserr.c
  1938. sed 's/^X//' > syserr.c << '//END_OF_FILE'
  1939. X#include <useful.h>
  1940. X#include <funclist.h>
  1941. X
  1942. XVERSIONID("$Header: syserr.c,v 2.0 89/12/24 00:56:31 eric Exp $");
  1943. X
  1944. X/*
  1945. X**  SYSERR -- indicate a system error
  1946. X**
  1947. X**    Parameters:
  1948. X**        m -- the printf() message to print.
  1949. X**        a, b, c, d, e -- parameters to the message
  1950. X**
  1951. X**    Returns:
  1952. X**        never
  1953. X**
  1954. X**    Side Effects:
  1955. X**        Terminates the process if no acceptable recover takes place.
  1956. X**
  1957. X**    Globals:
  1958. X**        SyserrFuncs -- a list of functions to call.
  1959. X**
  1960. X**    Author:
  1961. X**        Eric Allman
  1962. X**        University of California, Berkeley
  1963. X*/
  1964. X
  1965. X#ifdef FUNCLISTSTUFF
  1966. XFUNCLIST    *SyserrFuncs =        FUNCLISTNULL;
  1967. X#endif
  1968. X
  1969. XVOID
  1970. Xsyserr(m, a, b, c, d, e)
  1971. X    char *m;
  1972. X{
  1973. X    static BOOL exiting = FALSE;
  1974. X
  1975. X    /* print the error message */
  1976. X    _error_message(m, a, b, c, d, e);
  1977. X
  1978. X    /* if we recursively syserr during exit, drop out now! */
  1979. X    if (exiting)
  1980. X        _exit(1);
  1981. X
  1982. X#ifdef FUNCLISTSTUFF
  1983. X    /* call any possible cleanup functions */
  1984. X    funclist_call(SyserrFuncs, ARBNULL);
  1985. X#endif
  1986. X
  1987. X    /* try a clean exit */
  1988. X    exiting = TRUE;
  1989. X    exit(1);
  1990. X    /*NOTREACHED*/
  1991. X}
  1992. X /*
  1993. X**  USRERR -- print a user error
  1994. X**
  1995. X**    Parameters:
  1996. X**        m -- the printf() message to print.
  1997. X**        a, b, c, d, e -- parameters to the message
  1998. X**
  1999. X**    Returns:
  2000. X**        none.
  2001. X**
  2002. X**    Side Effects:
  2003. X**        clears the global error number.
  2004. X*/
  2005. X
  2006. X#ifdef FUNCLISTSTUFF
  2007. XFUNCLIST    *UsrerrFuncs =        FUNCLISTNULL;
  2008. X#endif
  2009. X
  2010. XVOID
  2011. Xusrerr(m, a, b, c, d, e)
  2012. X    char *m;
  2013. X{
  2014. X    extern int errno;
  2015. X
  2016. X    /* print the error message */
  2017. X    _error_message(m, a, b, c, d, e);
  2018. X
  2019. X#ifdef FUNCLISTSTUFF
  2020. X    /* allow cleanup actions */
  2021. X    funclist_call(UsrerrFuncs, ARBNULL);
  2022. X#endif
  2023. X
  2024. X    /* give us a clean slate */
  2025. X    errno = 0;
  2026. X}
  2027. X /*
  2028. X**  _ERROR_MESSAGE -- generic message printing routine.
  2029. X**
  2030. X**    Includes the program name with the message, as well as the
  2031. X**    various possible error codes.
  2032. X**
  2033. X**    Parameters:
  2034. X**        m -- the printf() message to print.
  2035. X**        a, b, c, d, e -- parameters to the message
  2036. X**
  2037. X**    Returns:
  2038. X**        none.
  2039. X**
  2040. X**    Side Effects:
  2041. X**        none.
  2042. X**
  2043. X**    Globals:
  2044. X**        ProgName -- the name of the program.
  2045. X*/
  2046. X
  2047. XSTATIC VOID
  2048. X_error_message(m, a, b, c, d, e)
  2049. X    char *m;
  2050. X{
  2051. X    extern char *ProgName;
  2052. X    int saveerr;
  2053. X    extern int errno;
  2054. X
  2055. X    saveerr = errno;
  2056. X    if (ProgName != CHARNULL)
  2057. X        fprintf(stderr, "%s: ", ProgName);
  2058. X    fprintf(stderr, m, a, b, c, d, e);
  2059. X    fprintf(stderr, "\n");
  2060. X    if (saveerr != 0)
  2061. X    {
  2062. X        errno = saveerr;
  2063. X        perror("System error");
  2064. X    }
  2065. X}
  2066. //END_OF_FILE
  2067. echo x - traceset.c
  2068. sed 's/^X//' > traceset.c << '//END_OF_FILE'
  2069. X#ifdef NODEBUG
  2070. X#undef NODEBUG
  2071. X#endif
  2072. X#define TRACESTUFF
  2073. X#include <useful.h>
  2074. X#include <ctype.h>
  2075. X
  2076. XVERSIONID("$Header: traceset.c,v 2.0 89/12/24 00:56:33 eric Exp $");
  2077. X
  2078. X/*
  2079. X**  TRACESET -- set trace flags
  2080. X**
  2081. X**    Parameters:
  2082. X**        s -- the string describing the trace flags desired.
  2083. X**
  2084. X**    Returns:
  2085. X**        none.
  2086. X**
  2087. X**    Side Effects:
  2088. X**        Sets values in the trace vector.
  2089. X**
  2090. X**    Globals:
  2091. X**        _TraceVect -- used by TRACE and TRACEF to determine the
  2092. X**            current trace flag settings.
  2093. X**
  2094. X**    Syntax:
  2095. X**        The argument points to a set of comma separated trace
  2096. X**        flag settings.  Each setting is a trace flag name, or
  2097. X**        a range of trace flags separated by a hyphen.  The
  2098. X**        setting may be followed by a dot and a level.  For
  2099. X**        example, "5,23-26.4" sets trace flag 5 to level 1 (the
  2100. X**        default), and flags 23 through 26 to level 4.
  2101. X**
  2102. X**        Trace flags names may be numeric or symbolic.  Symbolic
  2103. X**        names are looked up in the file "lib/traceflags", which
  2104. X**        is found somewhere in the search path.  This file has a
  2105. X**        simple "name <white-space> value" syntax.
  2106. X**
  2107. X**    Author:
  2108. X**        Eric Allman
  2109. X**        University of California, Berkeley
  2110. X*/
  2111. X
  2112. XSTATIC FILE    *_TraceSymFile =    FILENULL;
  2113. XSTATIC BOOL    _TraceSymCant =        FALSE;
  2114. Xunsigned char    _TraceVect[_TRACE_SIZE];
  2115. X
  2116. XVOID
  2117. Xtraceset(s)
  2118. X    char *s;
  2119. X{
  2120. X    int lo;
  2121. X    int hi;
  2122. X    int lev;
  2123. X
  2124. X    if (s == CHARNULL || *s == '\0')
  2125. X        s = "0-999";
  2126. X
  2127. X    do
  2128. X    {
  2129. X        /* get the low limit of the range */
  2130. X        lo = _tracetok(&s, TRUE);
  2131. X        if (lo < 0)
  2132. X            lo = 0;
  2133. X
  2134. X        /* get the high limit of the range */
  2135. X        if (*s == '-')
  2136. X            hi = _tracetok(&s, TRUE);
  2137. X        else
  2138. X            hi = lo;
  2139. X        if (hi >= _TRACE_SIZE)
  2140. X            hi = _TRACE_SIZE - 1;
  2141. X
  2142. X        /* get the trace level */
  2143. X        if (*s == '.')
  2144. X            lev = _tracetok(&s, FALSE);
  2145. X        else
  2146. X            lev = 1;
  2147. X        if (lev < 0)
  2148. X            lev = 1;
  2149. X
  2150. X        /* now do the actual setting */
  2151. X        while (lo <= hi)
  2152. X            _TraceVect[lo++] = lev;
  2153. X    } while (*s != '\0');
  2154. X
  2155. X    if (_TraceSymFile != FILENULL)
  2156. X    {
  2157. X        fclose(_TraceSymFile);
  2158. X        _TraceSymFile = FILENULL;
  2159. X    }
  2160. X}
  2161. X /*
  2162. X**  _TRACETOK -- extract a token
  2163. X**
  2164. X**    Parameters:
  2165. X**        sp -- an indirect pointer to the string form.  It is
  2166. X**            updated to point to the token terminator.
  2167. X**        symok -- if TRUE, a symbolic representation can be
  2168. X**            used.
  2169. X**
  2170. X**    Returns:
  2171. X**        The value of the token.
  2172. X**        -1 on error.
  2173. X**
  2174. X**    Side Effects:
  2175. X**        none.
  2176. X*/
  2177. X
  2178. XSTATIC int
  2179. X_tracetok(sp, symok)
  2180. X    char **sp;
  2181. X    BOOL symok;
  2182. X{
  2183. X    register char *s = *sp;
  2184. X    register char *tp;
  2185. X    char tbuf[MAXWORDLEN + 1];
  2186. X    char dbuf[MAXINPUTLINE];
  2187. X
  2188. X    /* skip leading cruft */
  2189. X    while (*s != '\0' && !isalnum(*s))
  2190. X        s++;
  2191. X
  2192. X    /* extract token */
  2193. X    for (tp = tbuf; isalnum(*s); *tp++ = *s++)
  2194. X        continue;
  2195. X    *tp = '\0';
  2196. X
  2197. X    /* drop trailing cruft */
  2198. X    while (isspace(*s))
  2199. X        s++;
  2200. X    *sp = s;
  2201. X
  2202. X    /* now decode token */
  2203. X    if (isdigit(tbuf[0]))
  2204. X        return (atoi(tbuf));
  2205. X    if (!symok)
  2206. X        return (-1);
  2207. X
  2208. X    /* look up symbol */
  2209. X    if (!_TraceSymCant && _TraceSymFile == FILENULL)
  2210. X    {
  2211. X        extern FILE *openpath ARGS((char *, char *, char *));
  2212. X
  2213. X        _TraceSymFile = openpath("lib/traceflags", "r", CHARNULL);
  2214. X    }
  2215. X    if (_TraceSymFile == FILENULL)
  2216. X    {
  2217. X        _TraceSymCant = TRUE;
  2218. X        return (-1);
  2219. X    }
  2220. X    rewind(_TraceSymFile);
  2221. X
  2222. X    /* search through the trace file for a matching line */
  2223. X    while (fgets(dbuf, sizeof dbuf, _TraceSymFile) != CHARNULL)
  2224. X    {
  2225. X        register char *ep;
  2226. X        extern char *_tracematch ARGS((char *, char *));
  2227. X
  2228. X        /* comment? */
  2229. X        if (dbuf[0] == '#' || dbuf[0] == '\n')
  2230. X            continue;
  2231. X
  2232. X        /* does it match? */
  2233. X        ep = _tracematch(tbuf, dbuf);
  2234. X        if (ep != CHARNULL)
  2235. X            return (atoi(ep));
  2236. X    }
  2237. X    return (-1);
  2238. X}
  2239. X
  2240. XSTATIC char *
  2241. X_tracematch(tp, dp)
  2242. X    register char *tp;
  2243. X    register char *dp;
  2244. X{
  2245. X    for ( ; *tp != '\0'; tp++, dp++)
  2246. X    {
  2247. X        /* if we have an exact match, continue trying */
  2248. X        if (*tp == *dp)
  2249. X            continue;
  2250. X
  2251. X        /* well, let's try a caseless match */
  2252. X        if (isupper(*tp) && tolower(*tp) == *dp)
  2253. X            continue;
  2254. X        if (isupper(*dp) && tolower(*dp) == *tp)
  2255. X            continue;
  2256. X
  2257. X        /* well foo...  I guess it doesn't match */
  2258. X        return (CHARNULL);
  2259. X    }
  2260. X
  2261. X    /* check the boundary conditions */
  2262. X    if (!isspace(*dp))
  2263. X        return (CHARNULL);
  2264. X
  2265. X    /* drop the trailing white space and return the pointer */
  2266. X    while (isspace(*dp))
  2267. X        dp++;
  2268. X    return (dp);
  2269. X}
  2270. //END_OF_FILE
  2271. echo x - stest.c
  2272. sed 's/^X//' > stest.c << '//END_OF_FILE'
  2273. X#include <useful.h>
  2274. X#include <parseargs.h>
  2275. X
  2276. XVERSIONID("$Header: stest.c,v 2.0 89/12/24 00:56:29 eric Exp $");
  2277. X
  2278. X/*
  2279. X**  STEST -- a simple test program for the argument parser
  2280. X**
  2281. X**    Author:
  2282. X**        Eric Allman
  2283. X**        University of California, Berkeley
  2284. X*/
  2285. X
  2286. Xint    RepCount;
  2287. Xchar    *Name;
  2288. Xchar    *DirName =    ".";
  2289. XBOOL    XFlag =        FALSE;
  2290. XBOOL    YFlag =        FALSE;
  2291. XBOOL    ZFlag =        FALSE;
  2292. Xchar    TabChar =    ':';
  2293. Xstruct namelist *Argv =    NULL;
  2294. Xstruct namelist *Groups = NULL;
  2295. X
  2296. XARGDESC    Args[] =
  2297. X{
  2298. X    ' ',    ARGREQ,        argStr,        __ &Name,    "Name",
  2299. X    'n',    ARGOPT,        argList,    __ &Groups,    "newsGROUP",
  2300. X    'c',    ARGOPT,        argInt,        __ &RepCount,    "REPcount",
  2301. X    'd',    ARGOPT,        argStr,        __ &DirName,    "DIRname",
  2302. X    'x',    ARGOPT,        argBool,    __ &XFlag,    "Xflag",
  2303. X    'y',    ARGOPT,        argBool,    __ &YFlag,    "Yflag",
  2304. X    'z',    ARGOPT,        argBool,    __ &ZFlag,    "Zflag",
  2305. X    't',    ARGOPT,        argChar,    __ &TabChar,    "TABchar",
  2306. X    ' ',    ARGOPT,        argList,    __ &Argv,    "File",
  2307. X    ENDOFARGS
  2308. X};
  2309. X
  2310. Xmain(argc, argv)
  2311. X    int argc;
  2312. X    char **argv;
  2313. X{
  2314. X    parseargs(argv, Args);
  2315. X
  2316. X    printf("Name = \"%s\", DirName = \"%s\", RepCount = %d,\n",
  2317. X        Name, DirName, RepCount);
  2318. X    printf("XFlag = %d, YFlag = %d, ZFlag = %d, TabChar=%03o;\n",
  2319. X        XFlag, YFlag, ZFlag, TabChar);
  2320. X
  2321. X    if(Groups) {
  2322. X        printf("Newsgroups: ");
  2323. X        while(Groups) {
  2324. X            printf("%s", Groups->nl_name);
  2325. X            Groups = Groups->nl_next;
  2326. X            if(Groups)
  2327. X                putchar(' ');
  2328. X            else
  2329. X                putchar('\n');
  2330. X        }
  2331. X    }
  2332. X
  2333. X    if(Argv) {
  2334. X        printf("Remaining args: ");
  2335. X        while(Argv) {
  2336. X            printf("%s", Argv->nl_name);
  2337. X            Argv = Argv->nl_next;
  2338. X            if(Argv)
  2339. X                putchar(' ');
  2340. X            else
  2341. X                putchar('\n');
  2342. X        }
  2343. X    }
  2344. X    exit(0);
  2345. X}
  2346. //END_OF_FILE
  2347. echo x - ckalloc.3
  2348. sed 's/^X//' > ckalloc.3 << '//END_OF_FILE'
  2349. X.\" $Header: ckalloc.3,v 2.0 89/12/24 00:56:12 eric Exp $
  2350. X.TH CKALLOC 3
  2351. X.SH NAME
  2352. Xckalloc \- allocate memory safely
  2353. X.SH SYNOPSIS
  2354. Xvoid *ckalloc(size)
  2355. X.br
  2356. Xunsigned int size;
  2357. X.PP
  2358. X#include <funclist.h>
  2359. X.br
  2360. Xextern FUNCLIST *OutOfMemoryFuncs;
  2361. X.SH DESCRIPTION
  2362. X.I ckalloc
  2363. Xallocates memory from the heap in the same manner as
  2364. X.IR malloc (3).
  2365. XHowever, if sufficient memory is unavailable,
  2366. Xrecovery is attempted by calling the list of functions
  2367. Xindicated by the
  2368. X.I OutOfMemoryFuncs
  2369. Xglobal function list
  2370. X(see
  2371. X.IR funclist (3)
  2372. Xfor details).
  2373. XAfter these functions are called,
  2374. Xthe allocation is retried.
  2375. X.PP
  2376. XIf the second attempt fails,
  2377. X.I ckalloc
  2378. Ximmediately terminates the process with a message
  2379. Xusing
  2380. X.IR syserr (3).
  2381. X.SH SEE ALSO
  2382. Xmalloc(3),
  2383. Xfunclist(3),
  2384. Xsyserr(3)
  2385. X.SH AUTHOR
  2386. XEric Allman, University of California, Berkeley
  2387. //END_OF_FILE
  2388. echo x - funclist.3
  2389. sed 's/^X//' > funclist.3 << '//END_OF_FILE'
  2390. X.\" $Header: funclist.3,v 2.0 89/12/24 00:56:22 eric Exp $
  2391. X.TH FUNCLIST 3
  2392. X.SH NAME
  2393. Xfunclist_add, funclist_call \- manipulate lists of function pointers
  2394. X.SH SYNOPSIS
  2395. X#include <funclist.h>
  2396. X.PP
  2397. Xvoid funclist_add(flp, func, arg1)
  2398. X.br
  2399. XFUNCLIST **flp;
  2400. X.br
  2401. Xvoid (*func)(void *, void *);
  2402. X.br
  2403. Xvoid *arg1;
  2404. X.PP
  2405. Xvoid funclist_call(fl, arg2)
  2406. X.br
  2407. XFUNCLIST *fl;
  2408. X.br
  2409. Xvoid *arg2;
  2410. X.SH DESCRIPTION
  2411. XA
  2412. X.I "function list"
  2413. Xis a linked list of function pointers
  2414. Xthat can be invoked at some future time.
  2415. XThese are often used to handle exceptional conditions
  2416. Xin generic library routines.
  2417. XThe implementation is not particularly efficient;
  2418. Xthese are intended primarily to allow flexible recovery
  2419. Xfrom relatively rare error conditions.
  2420. X.PP
  2421. XFunction lists are declared using:
  2422. X.PP
  2423. X    FUNCLIST *FuncListHead = FUNCLISTNULL;
  2424. X.PP
  2425. XFunctions are added to the list using:
  2426. X.PP
  2427. X    funclist_add(&FuncListHead, &func, arg1)
  2428. X.PP
  2429. Xwhere ``func'' is the name of the function to be invoked.
  2430. XThe
  2431. X.I arg1
  2432. Xargument is passed as the first parameter to the function when it is called,
  2433. Xand is otherwise uninterpreted.
  2434. X.PP
  2435. XFunction lists are invoked using:
  2436. X.PP
  2437. X    funclist_call(FuncListHead, arg2)
  2438. X.PP
  2439. XFunctions are invoked in the opposite order of their addition
  2440. Xto the function list.
  2441. XEach function is called as:
  2442. X.PP
  2443. X    func(arg1, arg2);
  2444. X.PP
  2445. XThat is, the first argument is from the addition to the list,
  2446. Xand the second is from the invocation.
  2447. X.SH BUGS
  2448. XThere should be some way to remove functions from the list.
  2449. X.SH AUTHOR
  2450. XEric Allman, University of California, Berkeley.
  2451. //END_OF_FILE
  2452. echo x - openpath.3
  2453. sed 's/^X//' > openpath.3 << '//END_OF_FILE'
  2454. X.\" $Header: openpath.3,v 2.0 89/12/24 00:56:24 eric Exp $
  2455. X.TH OPENPATH 3
  2456. X.SH NAME
  2457. Xopenpath \- open a file, searching through a search path
  2458. X.SH SYNOPSIS
  2459. XFILE *openpath(fname, mode, path)
  2460. X.br
  2461. Xchar *fname;
  2462. X.br
  2463. Xchar *mode;
  2464. X.br
  2465. Xchar *path;
  2466. X.PP
  2467. Xextern char *DefaultPath;
  2468. X.SH DESCRIPTION
  2469. X.I openpath
  2470. Xopens a file like
  2471. X.IR fopen (3),
  2472. Xexcept it uses a search path.
  2473. XA FILE pointer is returned for the first file matching the name
  2474. Xthat could be opened
  2475. Xin the search path.
  2476. XIf no file name matches,
  2477. XFILENULL is returned.
  2478. X.PP
  2479. XThe
  2480. X.I mode
  2481. Xis passed directly to
  2482. X.IR fopen (3).
  2483. X.PP
  2484. XThe
  2485. X.I path
  2486. Xis a colon-separated list of possible directories.
  2487. XEach element of the path can begin with a tilde (``~'')
  2488. Xto interpolate the
  2489. X$HOME
  2490. Xenvironment variable.
  2491. XZero length entries indicate the current directory.
  2492. XIf the path is not specified (CHARNULL),
  2493. Xthe external variable
  2494. X.I DefaultPath
  2495. Xis used.
  2496. XThis is set from the
  2497. X$ROOTPATH
  2498. Xenvironment variable.
  2499. XIf this is not set, a system default is used,
  2500. Xusually ``/usr/local:/usr:~:''.
  2501. X.SH SEE ALSO
  2502. Xfopen(3)
  2503. X.SH AUTHOR
  2504. XEric Allman, University of California, Berkeley
  2505. //END_OF_FILE
  2506. echo x - parseargs.3
  2507. sed 's/^X//' > parseargs.3 << '//END_OF_FILE'
  2508. X.\" $Header: parseargs.3,v 2.0 89/12/24 00:56:26 eric Exp $
  2509. X.TH PARSEARGS 3
  2510. X.SH NAME
  2511. Xparseargs, usage \- parse command line argument vectors
  2512. X.SH SYNOPSIS
  2513. X#include <parseargs.h>
  2514. X.PP
  2515. Xvoid parseargs(argv, argd)
  2516. X.br
  2517. Xchar *argvp[];
  2518. X.br
  2519. XARGDESC argd[];
  2520. X.PP
  2521. Xvoid usage(argd)
  2522. X.SH DESCRIPTION
  2523. XGiven a vector of string-valued arguments
  2524. Xsuch as that passed to
  2525. X.I main
  2526. Xand a vector describing the possible arguments,
  2527. X.I parseargs
  2528. Xmatches actual arguments to possible arguments,
  2529. Xconverts values to the desired type,
  2530. Xand diagnoses problems such as
  2531. Xmissing arguments,
  2532. Xextra arguments,
  2533. Xand argument values that are syntactically incorrect.
  2534. X.PP
  2535. XWhen invoked interactively,
  2536. Xunder the UNIX operating system and
  2537. Xif parseargs has been compiled for interactive operation,
  2538. X.I parseargs
  2539. Xprompts the user for argument values that are
  2540. Xrequired but are not given on the command line,
  2541. Xand values that are supplied but syntactically incorrect.
  2542. X.PP
  2543. XBy default this option is not compiled in to avoid problems in
  2544. Xshell scripts, where a program unexpectedly going into interactive
  2545. Xmode might tun out to be a little disconcerting.
  2546. X.PP
  2547. XGiven a description of possible arguments,
  2548. X.I usage
  2549. Xprints a reasonably friendly version of this description.
  2550. X.PP
  2551. XThe argument description vector
  2552. Xcontains one entry for each possible flag.
  2553. XEach entry has five fields:
  2554. X.IP name \w'prompt'u+2n
  2555. XThe single character name of the associated flag.
  2556. XFor example, to indicate that the program is expecting a ``\-x'' flag,
  2557. Xthis field would contain \'x\'.
  2558. XPositional arguments (those without a ``\-\fIx\fP'' prefix)
  2559. Xare indicated by passing a ``space'' character.
  2560. X.IP flags
  2561. XFlags modifying the semantics of this entry,
  2562. XThese should have one of
  2563. XARGREQ
  2564. Xto indicate a required argument or
  2565. XARGOPT
  2566. Xto indicate an optional argument.
  2567. XARGHIDDEN
  2568. Xcan be ``ored'' in to indicate a flag that should not be printed
  2569. Xin usage messages \(em
  2570. Xfor example, flags intended for internal debugging purposes.
  2571. X.IP type
  2572. XThe type of the argument.
  2573. XThis is actually a pointer to a function, as described below.
  2574. XStandard types include
  2575. XargBool (Boolean flags),
  2576. XargStr (string-valued arguments),
  2577. XargList (a LIFO list of string-valued arguments),
  2578. XargChar (char-valued arguments),
  2579. XargInt (native integer arguments),
  2580. XargShort (short integer arguments),
  2581. XargLong (long integer arguments),
  2582. XargFloat (short floating point arguments),
  2583. Xand
  2584. XargDouble (long floating point arguments).
  2585. X.IP valp
  2586. XA pointer to the variable that should receive the converted value.
  2587. XSince this is typed as ``pointer to anything'',
  2588. Xthis field should be preceded with a double underscore (``_\|_'')
  2589. X(a macro defined in parseargs.h)
  2590. Xto perform the appropriate type cast.
  2591. X.IP prompt
  2592. XThe string used when prompting interactively for argument values,
  2593. Xand printed in usage messages.
  2594. X.PP
  2595. XThe list of arguments is terminated using ENDOFARGS.
  2596. X.PP
  2597. XFor example, consider the description:
  2598. X.RS
  2599. X.PP
  2600. X.nf
  2601. Xint    RepCount =    2;
  2602. XBOOL    Verbose =    FALSE;
  2603. Xchar    *InFile;
  2604. Xchar    *OutFile =    CHARNULL;
  2605. XBOOL    XRated =    FALSE;
  2606. Xstruct namelist *Files = NULL;
  2607. X
  2608. XARGDESC Args[] =
  2609. X{
  2610. X    'c',    ARGOPT,        argInt,        __ &RepCount,    "REPcount",
  2611. X    'v',    ARGOPT,        argBool,    __ &Verbose,    "Verbose",
  2612. X    ' ',    ARGREQ,        argStr,        __ &InFile,    "INPUTfile",
  2613. X    ' ',    ARGOPT,        argStr,        __ &OutFile,    "OUTPUTfile",
  2614. X    'X',    ARGHIDDEN,    argBool,    __ &XRated,    "XratedMODE",
  2615. X    ' ',    ARGOPT,        argList,    __ &Files,    "File",
  2616. X    ENDOFARGS
  2617. X};
  2618. X.fi
  2619. X.RE
  2620. X.PP
  2621. XThis describes a program accepting up to three flag arguments and
  2622. Xone or two positional arguments, plus a list of additional file arguments.
  2623. XOnly the first positional argument is required.
  2624. XThe possible flags (in UNIX) are:
  2625. X.TP
  2626. X\fB\-c\fP \fIcount\fP
  2627. XAn integer repetition count.
  2628. XThis defaults to two.
  2629. X.TP
  2630. X\fB\-v\fP
  2631. XA Boolean ``verbose'' flag.
  2632. XIt defaults to FALSE.
  2633. X.TP
  2634. X\fB\-X\fP
  2635. XA Boolean ``X Rated'' flag.
  2636. XThis is not printed in the usage message.
  2637. X.PP
  2638. XThe two positional arguments are both strings, as is the final list.
  2639. XIn AmigaDOS, the options would be
  2640. X\fBREP\fP \fBcount\fP,
  2641. X\fBV\fP, and 
  2642. X\fXMODE\fP.
  2643. X.SH ARGUMENT TYPE FUNCTIONS
  2644. XThe argument types recognized by
  2645. X.I parseargs
  2646. Xcan be extended by adding new type functions.
  2647. XArgument type functions are declared as:
  2648. X.RS
  2649. X.PP
  2650. X.nf
  2651. XBOOL argXxx(argd, argp, copyf)
  2652. X    ARGDESC *argd;
  2653. X    char *argp;
  2654. X    BOOL copyf;
  2655. X.fi
  2656. X.RE
  2657. X.PP
  2658. XThe
  2659. X.I argd
  2660. Xargument points to the descriptor for the argument being converted.
  2661. XIts main use is to find the location in which to store the converted value,
  2662. Xlocated in argd\(->ad_valp.
  2663. XThe string value to be converted is passed in
  2664. X.IR argp .
  2665. XThe
  2666. X.I copyf
  2667. Xflag is TRUE if the
  2668. X.I argp
  2669. Xstring value must be copied when saved.
  2670. XMost non-string types are copied implicitly
  2671. X(for example, integer arguments are stored in binary form,
  2672. Xso the original string value need not be saved),
  2673. Xso this argument can usually be ignored.
  2674. XPut simply, this flag is
  2675. XTRUE
  2676. Xwhen
  2677. X.I argp
  2678. Xpoints to a temporary buffer area.
  2679. X.PP
  2680. XThe type function successfully converts the value,
  2681. Xit should return
  2682. XTRUE.
  2683. XOtherwise,
  2684. Xit should print a message using
  2685. X.IR usrerr (3)
  2686. Xand return FALSE. This message should be of the form
  2687. X\fB"invalid xxxx option 'yyyy' for Zzzz"\fP, where xxxx is the type of the
  2688. Xoption, yyyy is the string passed in vp, and zzzz is the name (taken from
  2689. X\fBad->ad_prompt\fP).
  2690. X.PP
  2691. XFor example, a type function that took a filename
  2692. Xand stored an open file pointer might be coded as:
  2693. X.RS
  2694. X.PP
  2695. X.nf
  2696. X/*ARGSUSED*/
  2697. XBOOL
  2698. XargReadFile(argd, argp, copyf)
  2699. X    register ARGDESC *argd;
  2700. X    register char *argp;
  2701. X    BOOL copyf;
  2702. X{
  2703. X    register FILE *fp;
  2704. X
  2705. X    fp = fopen(argp, "r");
  2706. X    if (fp == NULL)
  2707. X    {
  2708. X        usrerr("cannot open '%s' for reading as %s",
  2709. X            argp, argd->ad_prompt);
  2710. X        return (FALSE);
  2711. X    }
  2712. X    *(FILE *) argd->ad_valp = fp;
  2713. X    return (TRUE);
  2714. X}
  2715. X.fi
  2716. X.RE
  2717. X.SH SEE ALSO
  2718. Xsyserr(3)
  2719. X.br
  2720. XThe ``C Advisor'' column in
  2721. X.ul
  2722. XUNIX Review
  2723. XVol. 7 No. 11.
  2724. X.SH AUTHOR
  2725. XEric Allman, University of California, Berkeley
  2726. X.SH MODIFICATIONS
  2727. XModified to accept a vector of arguments, better error messages,
  2728. Xand AmigaDOS version by Peter da Silva.
  2729. //END_OF_FILE
  2730. echo x - syserr.3
  2731. sed 's/^X//' > syserr.3 << '//END_OF_FILE'
  2732. X.\" $Header: syserr.3,v 2.0 89/12/24 00:56:30 eric Exp $
  2733. X.TH SYSERR 3
  2734. X.SH NAME
  2735. Xsyserr, usrerr \- display error messages
  2736. X.SH SYNOPSIS
  2737. Xvoid syserr(msg, arg1, ...)
  2738. X.br
  2739. Xchar *msg;
  2740. X.br
  2741. Xvoid *arg1;
  2742. X.PP
  2743. Xvoid usrerr(msg, arg1, ...)
  2744. X.PP
  2745. X#include <funclist.h>
  2746. X.br
  2747. Xextern FUNCLIST *SyserrFuncs;
  2748. X.br
  2749. Xextern FUNCLIST *UsrerrFuncs;
  2750. X.PP
  2751. Xextern char *ProgName;
  2752. X.SH DESCRIPTION
  2753. XThese routines print error messages.
  2754. XUnrecoverable errors should be sent using
  2755. X.IR syserr ,
  2756. Xwhich is guaranteed to never return.
  2757. XRecoverable errors can be printed using
  2758. X.IR usrerr .
  2759. X.PP
  2760. XBoth routines label the message with the contents of the
  2761. X.I ProgName
  2762. Xvariable, which is set by
  2763. X.IR parseargs (3)
  2764. Xto the name of the invoking program.
  2765. XThe
  2766. X.I msg
  2767. Xand up to five arguments are passed to
  2768. X.IR fprintf (3)
  2769. Xto be printed.
  2770. XThe message should
  2771. X.I not
  2772. Xcontain a trailing newline;
  2773. Xthis is added internally.
  2774. XThe contents of the
  2775. X.I errno
  2776. Xglobal variable is then appended to the message.
  2777. X.PP
  2778. XAfter printing the message,
  2779. X.I syserr
  2780. Xinvokes the
  2781. X.I SyserrFuncs
  2782. Xfunction list.
  2783. XA member function can attempt to clean up and return to a top loop
  2784. Xusing
  2785. X.IR longjmp (3)
  2786. Xor some similar mechanism.
  2787. XIf the function list returns normally,
  2788. Xthe process is terminated.
  2789. X.PP
  2790. XAfter
  2791. X.I usrerr
  2792. Xprints the message,
  2793. Xit invokes the
  2794. X.I UsrerrFuncs
  2795. Xfunction list.
  2796. XMember functions can use non-local jumps if a ``quick abort'' policy
  2797. Xis desired.
  2798. XIf this function list returns,
  2799. X.I usrerr
  2800. Xreturns to the caller.
  2801. XThe global
  2802. X.I errno
  2803. Xvariable is reset to zero.
  2804. X.SH BUGS
  2805. XShould allow an arbitrary number of arguments.
  2806. X.PP
  2807. XMessages printed by
  2808. X.I syserr
  2809. Xshould probably also be logged using
  2810. X.IR syslog (3)
  2811. Xor the equivalent.
  2812. X.PP
  2813. XIt is possible to get recursive calls to
  2814. X.I syserr
  2815. Xif one of the
  2816. X.I SyserrFuncs
  2817. Xcalls
  2818. X.IR syserr .
  2819. XSimilar comments apply to
  2820. X.IR usrerr .
  2821. X.SH SEE ALSO
  2822. Xsyslog(3),
  2823. Xfunclist(3),
  2824. Xlongjmp(3),
  2825. Xexit(3)
  2826. //END_OF_FILE
  2827. echo x - trace.3
  2828. sed 's/^X//' > trace.3 << '//END_OF_FILE'
  2829. X.\" $Header: trace.3,v 2.0 89/12/24 00:56:31 eric Exp $
  2830. X.TH TRACE 3
  2831. X.SH NAME
  2832. XTRACE, TRACEF, traceset \- trace package
  2833. X.SH SYNOPSIS
  2834. X#include <useful.h>
  2835. X.PP
  2836. XBOOL TRACEF(flag, level)
  2837. X.br
  2838. Xint flag;
  2839. X.br
  2840. Xint level;
  2841. X.PP
  2842. XTRACE(flag, level, (\fIprintf arguments\fP));
  2843. X.PP
  2844. Xvoid traceset(tracestring)
  2845. X.br
  2846. Xchar *tracestring;
  2847. X.SH DESCRIPTION
  2848. XThe
  2849. X.I traceset
  2850. Xroutine and the
  2851. X.I TRACE
  2852. Xand
  2853. X.I TRACEF
  2854. Xmacros implement a simple trace flag package.
  2855. XA large number of trace flags
  2856. X(200 default)
  2857. Xcan each be set to a trace level
  2858. Xvarying from zero
  2859. X(no tracing for this flag)
  2860. Xto 255
  2861. X(full tracing).
  2862. X.PP
  2863. XThe
  2864. X.I TRACEF
  2865. Xmacro tests whether the specified flag is set to at least the indicated level.
  2866. XFor example:
  2867. X.PP
  2868. X    if (TRACEF(24, 3))
  2869. X.PP
  2870. Xtests flag 24; if it is set to 3 or higher,
  2871. Xthe
  2872. X.B if
  2873. Xstatement succeeds.
  2874. X.PP
  2875. XThe
  2876. X.I TRACE
  2877. Xmacro incorporates a
  2878. X.IR printf (3)
  2879. Xstatement.
  2880. XFor example, the code:
  2881. X.PP
  2882. X    TRACE(24, 3, ("xyzzy = %d\n", xyzzy));
  2883. X.PP
  2884. XPrints the ``xyzzy'' variable
  2885. Xwhen trace flag 24 is set to level 3 or higher.
  2886. XThe extra set of parentheses is important.
  2887. X.PP
  2888. XFlags can be adjusted using the
  2889. X.I traceset
  2890. Xroutine.
  2891. XThis parses the trace string, setting indicated flags as it goes.
  2892. XThe string is a comma-separated list of trace settings.
  2893. XEach setting has the syntax:
  2894. X.PP
  2895. X    flag[\-flag][.level]
  2896. X.PP
  2897. XIf the level is omitted, one is assumed.
  2898. XIf only one flag is indicated,
  2899. Xit is set individually.
  2900. XIf a range of flags is given,
  2901. Xall flags inclusively between the two values are set.
  2902. XFor example:
  2903. X.PP
  2904. X    20\-29.2
  2905. X.PP
  2906. Xsets the ten flags numbered between 20 and 29 to level 2.
  2907. X.PP
  2908. XFlag names can be symbolic.
  2909. XSymbolic names are looked up in the file
  2910. X``<searchpath>/lib/traceflags'',
  2911. Xwhere
  2912. X<searchpath>
  2913. Xis the default search path used by
  2914. X.IR openpath (3).
  2915. XThis file is a series of lines, each containing a flag name,
  2916. Xwhite space,
  2917. Xand the flag value.
  2918. XBlank lines
  2919. Xand lines beginning with `#' are ignored.
  2920. XCase is ignored in flag names.
  2921. X.SH SEE ALSO
  2922. Xopenpath(3),
  2923. Xparseargs(3)
  2924. X.SH AUTHOR
  2925. XEric Allman, University of California, Berkeley
  2926. //END_OF_FILE
  2927. echo "End of archive."
  2928. # end of archive.
  2929. exit 0
  2930. ---
  2931.  _--_|\  Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
  2932. /      \
  2933. \_.--._/ Xenix Support -- it's not just a job, it's an adventure!
  2934.       v  "Have you hugged your wolf today?" `-_-'
  2935.